diff --git a/.hgignore b/.hgignore index 5f1db1f6f3b1..831d844896f7 100644 --- a/.hgignore +++ b/.hgignore @@ -198,3 +198,7 @@ tps_result\.json # Ignore the build directories of WebRender standalone builds. gfx/wr/target/ + +# Ignore this files in certviewer +toolkit/components/certviewer/content/node_modules/ +toolkit/components/certviewer/content/package-lock.json diff --git a/Cargo.lock b/Cargo.lock index 6bf571c2f579..406d4baaa510 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -106,7 +106,7 @@ dependencies = [ "mio-named-pipes 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "scoped-tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.88 (git+https://github.com/servo/serde?branch=deserialize_from_enums10)", + "serde_derive 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-uds 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -315,7 +315,7 @@ dependencies = [ "filetime_win 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "guid_win 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.88 (git+https://github.com/servo/serde?branch=deserialize_from_enums10)", + "serde_derive 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (git+https://github.com/froydnj/winapi-rs?branch=aarch64)", ] @@ -976,7 +976,7 @@ dependencies = [ "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.88 (git+https://github.com/servo/serde?branch=deserialize_from_enums10)", + "serde_derive 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (git+https://github.com/froydnj/winapi-rs?branch=aarch64)", ] @@ -1030,7 +1030,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "euclid" -version = "0.19.5" +version = "0.19.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "euclid_macros 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1183,7 +1183,7 @@ dependencies = [ "mozversion 0.2.0", "regex 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.88 (git+https://github.com/servo/serde?branch=deserialize_from_enums10)", + "serde_derive 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", "uuid 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "webdriver 0.39.0", @@ -1715,7 +1715,7 @@ version = "0.0.1" dependencies = [ "app_units 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "cssparser 0.25.7 (registry+https://github.com/rust-lang/crates.io-index)", - "euclid 0.19.5 (registry+https://github.com/rust-lang/crates.io-index)", + "euclid 0.19.9 (registry+https://github.com/rust-lang/crates.io-index)", "hashglobe 0.1.0", "selectors 0.21.0", "servo_arc 0.1.1", @@ -1911,7 +1911,7 @@ dependencies = [ "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.88 (git+https://github.com/servo/serde?branch=deserialize_from_enums10)", + "serde_derive 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)", "syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)", "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (git+https://github.com/froydnj/winapi-rs?branch=aarch64)", @@ -2191,6 +2191,25 @@ dependencies = [ "winapi 0.3.6 (git+https://github.com/froydnj/winapi-rs?branch=aarch64)", ] +[[package]] +name = "peek-poke" +version = "0.2.0" +dependencies = [ + "euclid 0.19.9 (registry+https://github.com/rust-lang/crates.io-index)", + "peek-poke-derive 0.2.0", +] + +[[package]] +name = "peek-poke-derive" +version = "0.2.0" +dependencies = [ + "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)", + "synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "peeking_take_while" version = "0.1.2" @@ -2252,7 +2271,7 @@ version = "0.13.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "binary-space-partition 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "euclid 0.19.5 (registry+https://github.com/rust-lang/crates.io-index)", + "euclid 0.19.9 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2573,7 +2592,7 @@ dependencies = [ "lmdb-rkv 0.11.4 (registry+https://github.com/rust-lang/crates.io-index)", "ordered-float 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.88 (git+https://github.com/servo/serde?branch=deserialize_from_enums10)", + "serde_derive 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2740,7 +2759,7 @@ name = "serde" version = "1.0.88" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde_derive 1.0.88 (git+https://github.com/servo/serde?branch=deserialize_from_enums10)", + "serde_derive 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2754,7 +2773,7 @@ dependencies = [ [[package]] name = "serde_derive" version = "1.0.88" -source = "git+https://github.com/servo/serde?branch=deserialize_from_enums10#84b2795d2a7b5312125a99b1ef11c67fd8d17c35" +source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2926,7 +2945,7 @@ dependencies = [ "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "cssparser 0.25.7 (registry+https://github.com/rust-lang/crates.io-index)", "derive_more 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", - "euclid 0.19.5 (registry+https://github.com/rust-lang/crates.io-index)", + "euclid 0.19.9 (registry+https://github.com/rust-lang/crates.io-index)", "fallible 0.0.1", "fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "hashglobe 0.1.0", @@ -2987,7 +3006,7 @@ dependencies = [ "app_units 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "cssparser 0.25.7 (registry+https://github.com/rust-lang/crates.io-index)", - "euclid 0.19.5 (registry+https://github.com/rust-lang/crates.io-index)", + "euclid 0.19.9 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "malloc_size_of 0.0.1", "malloc_size_of_derive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3575,7 +3594,7 @@ dependencies = [ "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.88 (git+https://github.com/servo/serde?branch=deserialize_from_enums10)", + "serde_derive 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", "tokio 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3598,7 +3617,7 @@ dependencies = [ "core-text 13.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "cstr 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "dwrote 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "euclid 0.19.5 (registry+https://github.com/rust-lang/crates.io-index)", + "euclid 0.19.9 (registry+https://github.com/rust-lang/crates.io-index)", "freetype 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "gleam 0.6.17 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3629,17 +3648,17 @@ name = "webrender_api" version = "0.60.0" dependencies = [ "app_units 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "bincode 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "core-foundation 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", "core-graphics 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)", "derive_more 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", - "euclid 0.19.5 (registry+https://github.com/rust-lang/crates.io-index)", + "euclid 0.19.9 (registry+https://github.com/rust-lang/crates.io-index)", "malloc_size_of_derive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "peek-poke 0.2.0", "serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)", "serde_bytes 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.88 (git+https://github.com/servo/serde?branch=deserialize_from_enums10)", + "serde_derive 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", "wr_malloc_size_of 0.0.1", ] @@ -3653,7 +3672,7 @@ dependencies = [ "core-foundation 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", "core-graphics 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)", "dwrote 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "euclid 0.19.5 (registry+https://github.com/rust-lang/crates.io-index)", + "euclid 0.19.9 (registry+https://github.com/rust-lang/crates.io-index)", "foreign-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "gleam 0.6.17 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3680,7 +3699,7 @@ version = "0.1.0" dependencies = [ "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.88 (git+https://github.com/servo/serde?branch=deserialize_from_enums10)", + "serde_derive 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3750,7 +3769,7 @@ name = "wr_malloc_size_of" version = "0.0.1" dependencies = [ "app_units 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "euclid 0.19.5 (registry+https://github.com/rust-lang/crates.io-index)", + "euclid 0.19.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3948,7 +3967,7 @@ dependencies = [ "checksum encoding_rs 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)" = "4155785c79f2f6701f185eb2e6b4caf0555ec03477cb4c70db67b465311620ed" "checksum env_logger 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0561146661ae44c579e993456bc76d11ce1e0c7d745e57b2fa7146b6e49fa2ad" "checksum error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff511d5dc435d703f4971bc399647c9bc38e20cb41452e3b9feb4765419ed3f3" -"checksum euclid 0.19.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d1a7698bdda3d7444a79d33bdc96e8b518d44ea3ff101d8492a6ca1207b886ea" +"checksum euclid 0.19.9 (registry+https://github.com/rust-lang/crates.io-index)" = "596b99621b9477e7a5f94d2d8dd13a9c5c302ac358b822c67a42b6f1054450e1" "checksum euclid_macros 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fdcb84c18ea5037a1c5a23039b4ff29403abce2e0d6b1daa11cf0bde2b30be15" "checksum failure 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6dd377bcc1b1b7ce911967e3ec24fa19c3224394ec05b54aa7b083d498341ac7" "checksum failure_derive 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "64c2d913fe8ed3b6c6518eedf4538255b989945c14c2a7d5cbff62a5e2120596" @@ -4107,7 +4126,7 @@ dependencies = [ "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" "checksum serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)" = "9f301d728f2b94c9a7691c90f07b0b4e8a4517181d9461be94c04bddeb4bd850" "checksum serde_bytes 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)" = "adb6e51a6b3696b301bc221d785f898b4457c619b51d7ce195a6d20baecb37b3" -"checksum serde_derive 1.0.88 (git+https://github.com/servo/serde?branch=deserialize_from_enums10)" = "" +"checksum serde_derive 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)" = "beed18e6f5175aef3ba670e57c60ef3b1b74d250d962a26604bff4c80e970dd4" "checksum serde_json 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)" = "44dd2cfde475037451fa99b7e5df77aa3cfd1536575fa8e7a538ab36dcde49ae" "checksum serde_repr 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "29a734c298df0346c4cd5919595981c266dabbf12dc747c85e1a95e96077a52b" "checksum serde_urlencoded 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "642dd69105886af2efd227f75a520ec9b44a820d65bc133a9131f7d229fd165a" diff --git a/Cargo.toml b/Cargo.toml index 0371d3aa312f..e20800e4fc6b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -58,7 +58,6 @@ codegen-units = 1 [patch.crates-io] libudev-sys = { path = "dom/webauthn/libudev-sys" } -serde_derive = { git = "https://github.com/servo/serde", branch = "deserialize_from_enums10" } winapi = { git = "https://github.com/froydnj/winapi-rs", branch = "aarch64" } packed_simd = { git = "https://github.com/hsivonen/packed_simd", branch = "rust_1_32" } diff --git a/browser/actors/PluginChild.jsm b/browser/actors/PluginChild.jsm index a3c35e27a507..150ba9c93e47 100644 --- a/browser/actors/PluginChild.jsm +++ b/browser/actors/PluginChild.jsm @@ -1229,10 +1229,5 @@ class PluginChild extends ActorChild { messageString, pluginID, }); - - // Remove the notification when the page is reloaded. - doc.defaultView.top.addEventListener("unload", event => { - this.hideNotificationBar("plugin-crashed"); - }); } } diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js index 4cb973882b74..2ca91f663e1e 100644 --- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -8944,58 +8944,39 @@ var gPrivateBrowsingUI = { // temporary fix until bug 463607 is fixed document.getElementById("Tools:Sanitize").setAttribute("disabled", "true"); - if (window.location.href == AppConstants.BROWSER_CHROME_URL) { - // Adjust the window's title - let docElement = document.documentElement; - if (!PrivateBrowsingUtils.permanentPrivateBrowsing) { - docElement.setAttribute( - "title", - docElement.getAttribute("title_privatebrowsing") - ); - docElement.setAttribute( - "titlemodifier", - docElement.getAttribute("titlemodifier_privatebrowsing") - ); - } + if (window.location.href != AppConstants.BROWSER_CHROME_URL) { + return; + } + + // Adjust the window's title + let docElement = document.documentElement; + if (!PrivateBrowsingUtils.permanentPrivateBrowsing) { docElement.setAttribute( - "privatebrowsingmode", - PrivateBrowsingUtils.permanentPrivateBrowsing - ? "permanent" - : "temporary" + "title", + docElement.getAttribute("title_privatebrowsing") ); - gBrowser.updateTitlebar(); + docElement.setAttribute( + "titlemodifier", + docElement.getAttribute("titlemodifier_privatebrowsing") + ); + } + docElement.setAttribute( + "privatebrowsingmode", + PrivateBrowsingUtils.permanentPrivateBrowsing ? "permanent" : "temporary" + ); + gBrowser.updateTitlebar(); - if (PrivateBrowsingUtils.permanentPrivateBrowsing) { - // Adjust the New Window menu entries - [ - { normal: "menu_newNavigator", private: "menu_newPrivateWindow" }, - ].forEach(function(menu) { - let newWindow = document.getElementById(menu.normal); - let newPrivateWindow = document.getElementById(menu.private); - if (newWindow && newPrivateWindow) { - newPrivateWindow.hidden = true; - newWindow.label = newPrivateWindow.label; - newWindow.accessKey = newPrivateWindow.accessKey; - newWindow.command = newPrivateWindow.command; - } - }); + if (PrivateBrowsingUtils.permanentPrivateBrowsing) { + // Adjust the New Window menu entries + let newWindow = document.getElementById("menu_newNavigator"); + let newPrivateWindow = document.getElementById("menu_newPrivateWindow"); + if (newWindow && newPrivateWindow) { + newPrivateWindow.hidden = true; + newWindow.label = newPrivateWindow.label; + newWindow.accessKey = newPrivateWindow.accessKey; + newWindow.command = newPrivateWindow.command; } } - - let urlBarSearchParam = - gURLBar.getAttribute("autocompletesearchparam") || ""; - if ( - !PrivateBrowsingUtils.permanentPrivateBrowsing && - !urlBarSearchParam.includes("disable-private-actions") - ) { - // Disable switch to tab autocompletion for private windows. - // We leave it enabled for permanent private browsing mode though. - urlBarSearchParam += " disable-private-actions"; - } - if (!urlBarSearchParam.includes("private-window")) { - urlBarSearchParam += " private-window"; - } - gURLBar.setAttribute("autocompletesearchparam", urlBarSearchParam); }, }; diff --git a/browser/base/content/test/static/browser_parsable_script.js b/browser/base/content/test/static/browser_parsable_script.js index 3f1bc2a177f4..1d3ab794baca 100644 --- a/browser/base/content/test/static/browser_parsable_script.js +++ b/browser/base/content/test/static/browser_parsable_script.js @@ -20,6 +20,8 @@ const kESModuleList = new Set([ /browser\/aboutlogins\/.*\.js$/, /browser\/protections.js$/, /browser\/lockwise-card.js$/, + /toolkit\/content\/global\/certviewer\/components\/.*\.js$/, + /toolkit\/content\/global\/certviewer\/.*\.js$/, ]); // Normally we would use reflect.jsm to get Reflect.parse. However, if diff --git a/browser/components/urlbar/UrlbarInput.jsm b/browser/components/urlbar/UrlbarInput.jsm index 2c50f65502c1..be0f4fa708e2 100644 --- a/browser/components/urlbar/UrlbarInput.jsm +++ b/browser/components/urlbar/UrlbarInput.jsm @@ -104,6 +104,7 @@ class UrlbarInput { this._textValueOnLastSearch = ""; this._resultForCurrentValue = null; this._suppressStartQuery = false; + this._suppressPrimaryAdjustment = false; this._untrimmedValue = ""; // This exists only for tests. @@ -118,7 +119,6 @@ class UrlbarInput { "setAttribute", "removeAttribute", "toggleAttribute", - "select", ]; const READ_ONLY_PROPERTIES = ["inputField", "editor"]; const READ_WRITE_PROPERTIES = [ @@ -308,6 +308,14 @@ class UrlbarInput { this.inputField.blur(); } + select() { + // See _on_select(). HTMLInputElement.select() dispatches a "select" + // event but does not set the primary selection. + this._suppressPrimaryAdjustment = true; + this.inputField.select(); + this._suppressPrimaryAdjustment = false; + } + /** * Converts an internal URI (e.g. a URI with a username or password) into one * which we can expose to the user. @@ -1551,7 +1559,22 @@ class UrlbarInput { } _on_select(event) { + // On certain user input, AutoCopyListener::OnSelectionChange() updates + // the primary selection with user-selected text (when supported). + // Selection::NotifySelectionListeners() then dispatches a "select" event + // under similar conditions via TextInputListener::OnSelectionChange(). + // This event is received here in order to replace the primary selection + // from the editor with text having the adjustments of + // _getSelectedValueForClipboard(), such as adding the scheme for the url. + // + // Other "select" events are also received, however, and must be excluded. if ( + // _suppressPrimaryAdjustment is set during select(). Don't update + // the primary selection because that is not the intent of user input, + // which may be new tab or urlbar focus. + this._suppressPrimaryAdjustment || + // The check on isHandlingUserInput filters out async "select" events + // from setSelectionRange(), which occur when autofill text is selected. !this.window.windowUtils.isHandlingUserInput || !Services.clipboard.supportsSelectionClipboard() ) { diff --git a/browser/components/urlbar/tests/browser/browser.ini b/browser/components/urlbar/tests/browser/browser.ini index fa70e0864654..20a16cb1e70f 100644 --- a/browser/components/urlbar/tests/browser/browser.ini +++ b/browser/components/urlbar/tests/browser/browser.ini @@ -72,6 +72,7 @@ skip-if = (os == 'mac' && os_version == '10.14') # bug 1554807 tags = clipboard [browser_percent_encoded.js] [browser_populateAfterPushState.js] +[browser_primary_selection_safe_on_new_tab.js] [browser_privateBrowsingWindowChange.js] [browser_raceWithTabs.js] skip-if = os == "linux" # Bug 1533807 diff --git a/browser/components/urlbar/tests/browser/browser_primary_selection_safe_on_new_tab.js b/browser/components/urlbar/tests/browser/browser_primary_selection_safe_on_new_tab.js new file mode 100644 index 000000000000..2eb5f3a5a6e2 --- /dev/null +++ b/browser/components/urlbar/tests/browser/browser_primary_selection_safe_on_new_tab.js @@ -0,0 +1,74 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +/** + * Verify that the primary selection is unaffected by opening a new tab. + * + * The steps here follow STR for regression + * https://bugzilla.mozilla.org/show_bug.cgi?id=1457355. + */ + +"use strict"; + +let tabs = []; +let supportsPrimary = Services.clipboard.supportsSelectionClipboard(); +let ClipboardHelper = Cc["@mozilla.org/widget/clipboardhelper;1"].getService( + Ci.nsIClipboardHelper +); +const NON_EMPTY_URL = "data:text/html,Hello"; +const TEXT_FOR_PRIMARY = "Text for PRIMARY selection"; + +add_task(async function() { + tabs.push( + await BrowserTestUtils.openNewForegroundTab(gBrowser, NON_EMPTY_URL) + ); + + // Bug 1457355 reproduced only when the url had a non-empty selection. + gURLBar.select(); + Assert.equal(gURLBar.inputField.selectionStart, 0); + Assert.equal( + gURLBar.inputField.selectionEnd, + gURLBar.inputField.value.length + ); + + if (supportsPrimary) { + ClipboardHelper.copyStringToClipboard( + TEXT_FOR_PRIMARY, + Services.clipboard.kSelectionClipboard + ); + } + + tabs.push( + await BrowserTestUtils.openNewForegroundTab({ + gBrowser, + opening: () => { + // Simulate tab open from user input such as keyboard shortcut or new + // tab button. + let userInput = window.windowUtils.setHandlingUserInput(true); + try { + BrowserOpenTab(); + } finally { + userInput.destruct(); + } + }, + waitForLoad: false, + }) + ); + + if (!supportsPrimary) { + info("Primary selection not supported. Skipping assertion."); + return; + } + + let primaryAsText = SpecialPowers.getClipboardData( + "text/unicode", + SpecialPowers.Ci.nsIClipboard.kSelectionClipboard + ); + Assert.equal(primaryAsText, TEXT_FOR_PRIMARY); +}); + +registerCleanupFunction(() => { + for (let tab of tabs) { + BrowserTestUtils.removeTab(tab); + } +}); diff --git a/browser/themes/shared/incontentprefs/syncDisconnect.css b/browser/themes/shared/incontentprefs/syncDisconnect.css index bab3dc687231..b267a3127cd5 100644 --- a/browser/themes/shared/incontentprefs/syncDisconnect.css +++ b/browser/themes/shared/incontentprefs/syncDisconnect.css @@ -11,7 +11,7 @@ } .deleteOptions { - border: thin solid lightgray; + border: 1px solid var(--in-content-box-border-color); padding: 1em; } @@ -20,7 +20,7 @@ } .deleteData { - color: gray; + color: var(--in-content-deemphasized-text); } .disconnectThrobber { diff --git a/devtools/client/application/application.css b/devtools/client/application/application.css index 478d57688efa..c6072356f53b 100644 --- a/devtools/client/application/application.css +++ b/devtools/client/application/application.css @@ -2,11 +2,23 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + /* +* Global styles +*/ +@import "resource://devtools/client/application/src/base.css"; + +/* +* Components +*/ @import "resource://devtools/client/application/src/components/App.css"; @import "resource://devtools/client/application/src/components/Worker.css"; @import "resource://devtools/client/application/src/components/WorkerList.css"; @import "resource://devtools/client/application/src/components/WorkerListEmpty.css"; + +/* +* Reset +*/ * { box-sizing: border-box; } diff --git a/devtools/client/application/src/base.css b/devtools/client/application/src/base.css new file mode 100644 index 000000000000..bfb13132806f --- /dev/null +++ b/devtools/client/application/src/base.css @@ -0,0 +1,61 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +:root { + /* Typography from Photon */ + /* See https://firefox-dev.tools/photon/visuals/typography.html */ + --body-10-font-size: 13px; + --body-10-font-weight: 400; + --body-20-font-size: 15px; + --body-20-font-weight: 400; + --body-20-font-weight-bold: 700; + --title-20-font-size: 17px; + --title-20-font-weight: 600; + --title-30-font-size: 22px; + --title-30-font-weight: 300; + + /* Global styles */ + --base-font-size: var(--body-10-font-size); + --base-font-weight: var(--body-10-font-weight); + --base-line-height: 1.8; + --list-line-height: 1.25; + + /* Global colours */ + --bg-color: var(--grey-10); + --text-color: var(--grey-90); + + /* Global layout vars */ + --base-unit: 4px; +} + +/* +* Reset some tags +*/ + +body { + margin: 0; + padding: 0; + line-height: var(--base-line-height); +} + +ul { + line-height: var(--list-line-height); +} + +a { + color: var(--theme-highlight-blue); + text-decoration: none; + cursor: pointer; +} + +h1, +.application--title { + font-size: var(--title-30-font-size); + font-weight: var(--title-30-font-weight); + line-height: var(--base-line-height); +} + +p { + margin: 0; +} diff --git a/devtools/client/application/src/components/App.css b/devtools/client/application/src/components/App.css index b2242f35dd14..6c2c1acabaf4 100644 --- a/devtools/client/application/src/components/App.css +++ b/devtools/client/application/src/components/App.css @@ -6,26 +6,10 @@ * General styles */ -h1 { - font-size: 22px; - font-weight: normal; -} - -a { - margin: 0 10px; -} - -a, -a:hover, -a:visited { - color: var(--theme-highlight-blue) !important; - cursor: pointer; -} - a.disabled-link, a.disabled-link:hover, a.disabled-link:visited { - opacity: 0.5 !important; + opacity: 0.5; cursor: not-allowed; } diff --git a/devtools/client/application/src/components/Worker.css b/devtools/client/application/src/components/Worker.css index f39753cc8faf..6a3f218f82b9 100644 --- a/devtools/client/application/src/components/Worker.css +++ b/devtools/client/application/src/components/Worker.css @@ -22,9 +22,8 @@ width: 100%; grid-column-gap: 0; padding: 1rem 0; - line-height: 1.5; - font-size: 1.2rem; + font-size: var(--body-10-font-size); } .worker:first-child { @@ -73,3 +72,8 @@ .worker__data__updated { color: var(--theme-text-color-alt); } + +.worker__link-start, +.worker__link-debug { + margin: 0 calc(var(--base-unit) * 2); +} diff --git a/devtools/client/application/src/components/Worker.js b/devtools/client/application/src/components/Worker.js index ed01d2bbf8db..f203c04ff534 100644 --- a/devtools/client/application/src/components/Worker.js +++ b/devtools/client/application/src/components/Worker.js @@ -154,7 +154,7 @@ class Worker extends Component { }, a({ onClick: !shallDisableLink ? this.debug : null, - className: `${linkClass} worker__debug-link js-debug-link`, + className: `${linkClass} worker__link-debug js-link-debug`, }) ); return link; @@ -174,7 +174,7 @@ class Worker extends Component { }, a({ onClick: this.start, - className: `worker__start-link js-start-link ${linkClass}`, + className: `worker__link-start js-link-start ${linkClass}`, }) ); return link; diff --git a/devtools/client/application/src/components/WorkerList.js b/devtools/client/application/src/components/WorkerList.js index 4c9f5c542dc4..be1277680c28 100644 --- a/devtools/client/application/src/components/WorkerList.js +++ b/devtools/client/application/src/components/WorkerList.js @@ -42,7 +42,12 @@ class WorkerList extends Component { return [ article( { className: "workers-container" }, - Localized({ id: "serviceworker-list-header" }, h1({})), + Localized( + { id: "serviceworker-list-header" }, + h1({ + className: "application--title", + }) + ), ul( {}, workers.map(worker => @@ -56,7 +61,7 @@ class WorkerList extends Component { ), Localized( { - id: "serviceworker-list-aboutdebugging2", + id: "serviceworker-list-aboutdebugging", a: a({ className: "aboutdebugging-plug__link", onClick: () => openTrustedLink("about:debugging#workers"), diff --git a/devtools/client/application/src/components/WorkerListEmpty.css b/devtools/client/application/src/components/WorkerListEmpty.css index cfd0f967811c..3822ee9923e2 100644 --- a/devtools/client/application/src/components/WorkerListEmpty.css +++ b/devtools/client/application/src/components/WorkerListEmpty.css @@ -3,16 +3,20 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ .worker-list-empty { - max-width: 65rem; - font-size: 1.2rem; - line-height: 1.25; + max-width: calc(var(--base-unit) * 179); + font-size: var(--body-10-font-size); color: var(--theme-toolbar-color); } .worker-list-empty__title { - font-size: 1.4rem; + font-size: var(--title-20-font-size); + font-weight: var(--title-20-font-weight); } +.worker-list-empty__title .external-link { + font-weight: var(--title-30-font-weight); +} + .worker-list-empty__tips { margin-inline-start: 2rem; } @@ -20,4 +24,4 @@ .worker-list-empty__tips__item { margin-block-start: 0.5rem; margin-block-end: 0.5rem; -} \ No newline at end of file +} diff --git a/devtools/client/application/src/components/WorkerListEmpty.js b/devtools/client/application/src/components/WorkerListEmpty.js index 6db0150bf97a..440f47e907da 100644 --- a/devtools/client/application/src/components/WorkerListEmpty.js +++ b/devtools/client/application/src/components/WorkerListEmpty.js @@ -13,7 +13,6 @@ const { const { a, article, - h1, li, p, ul, @@ -64,7 +63,7 @@ class WorkerListEmpty extends Component { onClick: () => this.openDocumentation(), }), }, - h1({ className: "worker-list-empty__title" }) + p({ className: "worker-list-empty__title" }) ), Localized({ id: "serviceworker-empty-suggestions" }, p({})), ul( diff --git a/devtools/client/application/src/moz.build b/devtools/client/application/src/moz.build index ba5b0aa05109..84b406abd9a7 100644 --- a/devtools/client/application/src/moz.build +++ b/devtools/client/application/src/moz.build @@ -10,6 +10,7 @@ DIRS += [ ] DevToolsModules( + 'base.css', 'constants.js', 'create-store.js', ) diff --git a/devtools/client/application/test/browser/browser_application_panel_debug-service-worker.js b/devtools/client/application/test/browser/browser_application_panel_debug-service-worker.js index ecc1119614ef..f1b777ffdd53 100644 --- a/devtools/client/application/test/browser/browser_application_panel_debug-service-worker.js +++ b/devtools/client/application/test/browser/browser_application_panel_debug-service-worker.js @@ -29,13 +29,13 @@ add_task(async function() { const container = getWorkerContainers(doc)[0]; info("Wait until the debug link is displayed and enabled"); await waitUntil(() => - container.querySelector(".js-debug-link:not(.worker__debug-link--disabled)") + container.querySelector(".js-link-debug:not(.worker__debug-link--disabled)") ); info("Click on the debug link and wait for the new toolbox to be ready"); const onToolboxReady = gDevTools.once("toolbox-ready"); - const debugLink = container.querySelector(".js-debug-link"); + const debugLink = container.querySelector(".js-link-debug"); debugLink.click(); const serviceWorkerToolbox = await onToolboxReady; diff --git a/devtools/client/application/test/browser/browser_application_panel_start-service-worker.js b/devtools/client/application/test/browser/browser_application_panel_start-service-worker.js index f0bafc28f858..88c62eb8a517 100644 --- a/devtools/client/application/test/browser/browser_application_panel_start-service-worker.js +++ b/devtools/client/application/test/browser/browser_application_panel_start-service-worker.js @@ -29,10 +29,10 @@ add_task(async function() { info("Wait until the start link is displayed and enabled"); const container = getWorkerContainers(doc)[0]; await waitUntil(() => - container.querySelector(".js-start-link:not(.disabled-link)") + container.querySelector(".js-link-start:not(.disabled-link)") ); info("Click the link and wait for the worker to start"); - const link = container.querySelector(".js-start-link"); + const link = container.querySelector(".js-link-start"); link.click(); await waitUntil( () => container.querySelector(".js-worker-status").textContent === "Running" @@ -61,9 +61,9 @@ add_task(async function() { info("Wait until the start link is displayed"); const container = getWorkerContainers(doc)[0]; - await waitUntil(() => container.querySelector(".js-start-link")); + await waitUntil(() => container.querySelector(".js-link-start")); ok( - container.querySelector(".js-start-link.disabled-link"), + container.querySelector(".js-link-start.disabled-link"), "Start link is disabled" ); diff --git a/devtools/client/debugger/test/mochitest/browser.ini b/devtools/client/debugger/test/mochitest/browser.ini index a3c9eb2faff4..6cf3ca16a768 100644 --- a/devtools/client/debugger/test/mochitest/browser.ini +++ b/devtools/client/debugger/test/mochitest/browser.ini @@ -803,7 +803,6 @@ skip-if = os == "win" [browser_dbg-react-app.js] skip-if = os == "win" [browser_dbg-wasm-sourcemaps.js] -skip-if = (os == "win") || os == ("linux") && debug # Bug 1561092 [browser_dbg-windowless-workers.js] [browser_dbg-windowless-workers-early-breakpoint.js] [browser_dbg-worker-scopes.js] diff --git a/devtools/client/inspector/grids/components/GridItem.js b/devtools/client/inspector/grids/components/GridItem.js index 1bab6807e923..6a7bf3a9630d 100644 --- a/devtools/client/inspector/grids/components/GridItem.js +++ b/devtools/client/inspector/grids/components/GridItem.js @@ -83,22 +83,8 @@ class GridItem extends PureComponent { this.props.onSetGridOverlayColor(this.props.grid.nodeFront, color); } - onGridCheckboxClick(e) { - // If the click was on the svg icon to select the node in the inspector, bail out. - const originalTarget = - e.nativeEvent && e.nativeEvent.explicitOriginalTarget; - if ( - originalTarget && - originalTarget.namespaceURI === "http://www.w3.org/2000/svg" - ) { - // We should be able to cancel the click event propagation after the following reps - // issue is implemented : https://github.com/firefox-devtools/reps/issues/95 . - e.preventDefault(); - return; - } - + onGridCheckboxClick() { const { grid, onToggleGridHighlighter } = this.props; - onToggleGridHighlighter(grid.nodeFront); } @@ -164,8 +150,11 @@ class GridItem extends PureComponent { onDOMNodeMouseOut: () => onHideBoxModelHighlighter(), onDOMNodeMouseOver: () => onShowBoxModelHighlighterForNode(grid.nodeFront), - onInspectIconClick: () => - this.onGridInspectIconClick(grid.nodeFront), + onInspectIconClick: (_, e) => { + // Stoping click propagation to avoid firing onGridCheckboxClick() + e.stopPropagation(); + this.onGridInspectIconClick(grid.nodeFront); + }, }) ), dom.div({ diff --git a/devtools/client/locales/en-US/netmonitor.properties b/devtools/client/locales/en-US/netmonitor.properties index c0a006d4b0c7..af702189fe89 100644 --- a/devtools/client/locales/en-US/netmonitor.properties +++ b/devtools/client/locales/en-US/netmonitor.properties @@ -645,9 +645,9 @@ netmonitor.ws.toolbar.frameType=Type # in the websocket frame table header, above the "size" column. netmonitor.ws.toolbar.size=Size -# LOCALIZATION NOTE (netmonitor.ws.toolbar.payload): This is the label displayed -# in the websocket frame table header, above the "payload" column. -netmonitor.ws.toolbar.payload=Payload +# LOCALIZATION NOTE (netmonitor.ws.toolbar.data): This is the label displayed +# in the websocket frame table header, above the "data" column. +netmonitor.ws.toolbar.data=Data # LOCALIZATION NOTE (netmonitor.ws.toolbar.opCode): This is the label displayed # in the websocket frame table header, above the "opCode" column. @@ -665,13 +665,49 @@ netmonitor.ws.toolbar.finBit=FinBit # in the websocket frame table header, above the "time" column. netmonitor.ws.toolbar.time=Time +# LOCALIZATION NOTE (netmonitor.ws.toolbar.clear): This is the label displayed +# in the websocket toolbar for the "Clear" button. +netmonitor.ws.toolbar.clear=Clear + +# LOCALIZATION NOTE (netmonitor.ws.toolbar.filterFreetext.label): This is the label +# displayed in the websocket toolbar for the frames filtering textbox. +netmonitor.ws.toolbar.filterFreetext.label=Filter Messages + +# LOCALIZATION NOTE (netmonitor.ws.toolbar.filterFreetext.key): This is the +# shortcut key to focus on the websocket toolbar frames filtering textbox +netmonitor.ws.toolbar.filterFreetext.key=CmdOrCtrl+E + +# LOCALIZATION NOTE (netmonitor.ws.context.all): This is the label displayed +# on the context menu that shows "All" WebSocket frames. +netmonitor.ws.context.all=All + +# LOCALIZATION NOTE (netmonitor.ws.context.all.accesskey): This is the access key +# for the "All" menu item displayed in the context menu in the websocket toolbar. +netmonitor.ws.context.all.accesskey=A + +# LOCALIZATION NOTE (netmonitor.ws.context.sent): This is the label displayed +# on the context menu that shows "Sent" WebSocket frames. +netmonitor.ws.context.sent=Sent + +# LOCALIZATION NOTE (netmonitor.ws.context.sent.accesskey): This is the access key +# for the "Sent" menu item displayed in the context menu in the websocket toolbar. +netmonitor.ws.context.sent.accesskey=S + +# LOCALIZATION NOTE (netmonitor.ws.context.received): This is the label displayed +# on the context menu that shows "Received" WebSocket frames. +netmonitor.ws.context.received=Received + +# LOCALIZATION NOTE (netmonitor.ws.context.received.accesskey): This is the access key +# for the "Received" menu item displayed in the context menu in the websocket toolbar. +netmonitor.ws.context.received.accesskey=R + # LOCALIZATION NOTE (netmonitor.tab.headers): This is the label displayed # in the network details pane identifying the headers tab. netmonitor.tab.headers=Headers -# LOCALIZATION NOTE (netmonitor.tab.webSockets): This is the label displayed -# in the network details pane identifying the webSockets tab. -netmonitor.tab.webSockets=WebSockets +# LOCALIZATION NOTE (netmonitor.tab.messages): This is the label displayed +# in the network details pane identifying the messages tab. +netmonitor.tab.messages=Messages # LOCALIZATION NOTE (netmonitor.tab.cookies): This is the label displayed # in the network details pane identifying the cookies tab. diff --git a/devtools/client/netmonitor/src/actions/selection.js b/devtools/client/netmonitor/src/actions/selection.js index 19dab473b449..941b86b39320 100644 --- a/devtools/client/netmonitor/src/actions/selection.js +++ b/devtools/client/netmonitor/src/actions/selection.js @@ -15,10 +15,11 @@ const PAGE_SIZE_ITEM_COUNT_RATIO = 5; /** * Select request with a given id. */ -function selectRequest(id) { +function selectRequest(id, httpChannelId) { return { type: SELECT_REQUEST, id, + httpChannelId, }; } diff --git a/devtools/client/netmonitor/src/actions/web-sockets.js b/devtools/client/netmonitor/src/actions/web-sockets.js index d450a4f52561..f28d7cea4e9a 100644 --- a/devtools/client/netmonitor/src/actions/web-sockets.js +++ b/devtools/client/netmonitor/src/actions/web-sockets.js @@ -8,8 +8,14 @@ const { WS_ADD_FRAME, WS_SELECT_FRAME, WS_OPEN_FRAME_DETAILS, + WS_CLEAR_FRAMES, + WS_TOGGLE_FRAME_FILTER_TYPE, + WS_SET_REQUEST_FILTER_TEXT, } = require("../constants"); +/** + * Add frame into state. + */ function addFrame(httpChannelId, data) { return { type: WS_ADD_FRAME, @@ -41,8 +47,43 @@ function openFrameDetails(open) { }; } +/** + * Clear all frames from the FrameListContent + * component belonging to the current channelId + */ +function clearFrames() { + return { + type: WS_CLEAR_FRAMES, + }; +} + +/** + * Show filtered frames from the FrameListContent + * component belonging to the current channelId + */ +function toggleFrameFilterType(filter) { + return { + type: WS_TOGGLE_FRAME_FILTER_TYPE, + filter, + }; +} + +/** + * Set filter text in toolbar. + * + */ +function setFrameFilterText(text) { + return { + type: WS_SET_REQUEST_FILTER_TEXT, + text, + }; +} + module.exports = { addFrame, selectFrame, openFrameDetails, + clearFrames, + toggleFrameFilterType, + setFrameFilterText, }; diff --git a/devtools/client/netmonitor/src/assets/styles/Toolbar.css b/devtools/client/netmonitor/src/assets/styles/Toolbar.css index 54838b3a9c31..867ebc1a4e90 100644 --- a/devtools/client/netmonitor/src/assets/styles/Toolbar.css +++ b/devtools/client/netmonitor/src/assets/styles/Toolbar.css @@ -14,11 +14,6 @@ min-height: var(--primary-toolbar-height); } -.requests-list-filter-buttons { - white-space: nowrap; - margin: 0 7px; -} - .devtools-button.devtools-pause-icon::before, .devtools-button.devtools-play-icon::before { margin-bottom: 1px; diff --git a/devtools/client/netmonitor/src/components/RequestListContent.js b/devtools/client/netmonitor/src/components/RequestListContent.js index a50add884264..e760b02bcec3 100644 --- a/devtools/client/netmonitor/src/components/RequestListContent.js +++ b/devtools/client/netmonitor/src/components/RequestListContent.js @@ -232,9 +232,9 @@ class RequestListContent extends Component { this.tooltip.hide(); } - onMouseDown(evt, id) { + onMouseDown(evt, id, channelId) { if (evt.button === LEFT_MOUSE_BUTTON) { - this.props.selectRequest(id); + this.props.selectRequest(id, channelId); } else if (evt.button === RIGHT_MOUSE_BUTTON) { this.props.onItemRightMouseButtonDown(id); } @@ -383,7 +383,8 @@ class RequestListContent extends Component { onContextMenu: this.onContextMenu, onFocusedNodeChange: this.onFocusedNodeChange, onDoubleClick: () => this.onDoubleClick(item), - onMouseDown: evt => this.onMouseDown(evt, item.id), + onMouseDown: evt => + this.onMouseDown(evt, item.id, item.channelId), onCauseBadgeMouseDown: () => onCauseBadgeMouseDown(item.cause), onSecurityIconMouseDown: () => onSecurityIconMouseDown(item.securityState), @@ -435,7 +436,8 @@ module.exports = connect( dispatch(Actions.selectDetailsPanelTab("stack-trace")); } }, - selectRequest: id => dispatch(Actions.selectRequest(id)), + selectRequest: (id, channelId) => + dispatch(Actions.selectRequest(id, channelId)), onItemRightMouseButtonDown: id => dispatch(Actions.rightClickRequest(id)), onItemMouseDown: id => dispatch(Actions.selectRequest(id)), /** diff --git a/devtools/client/netmonitor/src/components/TabboxPanel.js b/devtools/client/netmonitor/src/components/TabboxPanel.js index 551f0ec805ef..430efa730260 100644 --- a/devtools/client/netmonitor/src/components/TabboxPanel.js +++ b/devtools/client/netmonitor/src/components/TabboxPanel.js @@ -34,7 +34,7 @@ const COLLAPSE_DETAILS_PANE = L10N.getStr("collapseDetailsPane"); const CACHE_TITLE = L10N.getStr("netmonitor.tab.cache"); const COOKIES_TITLE = L10N.getStr("netmonitor.tab.cookies"); const HEADERS_TITLE = L10N.getStr("netmonitor.tab.headers"); -const WEBSOCKETS_TITLE = L10N.getStr("netmonitor.tab.webSockets"); +const MESSAGES_TITLE = L10N.getStr("netmonitor.tab.messages"); const PARAMS_TITLE = L10N.getStr("netmonitor.tab.params"); const RESPONSE_TITLE = L10N.getStr("netmonitor.tab.response"); const SECURITY_TITLE = L10N.getStr("netmonitor.tab.security"); @@ -96,7 +96,6 @@ class TabboxPanel extends Component { return null; } - const channelId = request.channelId; const showWebSocketsPanel = request.cause.type === "websocket" && Services.prefs.getBoolPref("devtools.netmonitor.features.webSockets") && @@ -135,11 +134,10 @@ class TabboxPanel extends Component { showWebSocketsPanel && TabPanel( { - id: PANELS.WEBSOCKETS, - title: WEBSOCKETS_TITLE, + id: PANELS.MESSAGES, + title: MESSAGES_TITLE, }, WebSocketsPanel({ - channelId, connector, }) ), diff --git a/devtools/client/netmonitor/src/components/websockets/FrameFilterMenu.js b/devtools/client/netmonitor/src/components/websockets/FrameFilterMenu.js new file mode 100644 index 000000000000..132c4eacd1d1 --- /dev/null +++ b/devtools/client/netmonitor/src/components/websockets/FrameFilterMenu.js @@ -0,0 +1,85 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; +const { PureComponent } = require("devtools/client/shared/vendor/react"); +const dom = require("devtools/client/shared/vendor/react-dom-factories"); +const PropTypes = require("devtools/client/shared/vendor/react-prop-types"); + +const { L10N } = require("devtools/client/netmonitor/src/utils/l10n.js"); + +// Menu +loader.lazyRequireGetter( + this, + "showMenu", + "devtools/client/shared/components/menu/utils", + true +); + +class FrameFilterMenu extends PureComponent { + static get propTypes() { + return { + frameFilterType: PropTypes.string.isRequired, + toggleFrameFilterType: PropTypes.func.isRequired, + }; + } + + constructor(props) { + super(props); + this.onShowFilterMenu = this.onShowFilterMenu.bind(this); + } + + onShowFilterMenu(event) { + const { frameFilterType, toggleFrameFilterType } = this.props; + + const menuItems = [ + { + id: "ws-frame-list-context-filter-all", + label: L10N.getStr("netmonitor.ws.context.all"), + accesskey: L10N.getStr("netmonitor.ws.context.all.accesskey"), + checked: frameFilterType === "all", + click: () => { + toggleFrameFilterType("all"); + }, + }, + { + id: "ws-frame-list-context-filter-sent", + label: L10N.getStr("netmonitor.ws.context.sent"), + accesskey: L10N.getStr("netmonitor.ws.context.sent.accesskey"), + checked: frameFilterType === "sent", + click: () => { + toggleFrameFilterType("sent"); + }, + }, + { + id: "ws-frame-list-context-filter-received", + label: L10N.getStr("netmonitor.ws.context.received"), + accesskey: L10N.getStr("netmonitor.ws.context.received.accesskey"), + checked: frameFilterType === "received", + click: () => { + toggleFrameFilterType("received"); + }, + }, + ]; + + showMenu(menuItems, { button: event.target }); + } + + render() { + const { frameFilterType } = this.props; + const title = L10N.getStr(`netmonitor.ws.context.${frameFilterType}`); + + return dom.button( + { + id: "frame-filter-menu", + className: "devtools-button devtools-dropdown-button", + title, + onClick: this.onShowFilterMenu, + }, + dom.span({ className: "title" }, title) + ); + } +} + +module.exports = FrameFilterMenu; diff --git a/devtools/client/netmonitor/src/components/websockets/FrameListColumnPayload.js b/devtools/client/netmonitor/src/components/websockets/FrameListColumnData.js similarity index 91% rename from devtools/client/netmonitor/src/components/websockets/FrameListColumnPayload.js rename to devtools/client/netmonitor/src/components/websockets/FrameListColumnData.js index f8d7d1a9ec98..b0a887b11d45 100644 --- a/devtools/client/netmonitor/src/components/websockets/FrameListColumnPayload.js +++ b/devtools/client/netmonitor/src/components/websockets/FrameListColumnData.js @@ -10,9 +10,9 @@ const PropTypes = require("devtools/client/shared/vendor/react-prop-types"); const { getFramePayload } = require("../../utils/request-utils"); /** - * Renders the "Payload" column of a WebSocket frame. + * Renders the "Data" column of a WebSocket frame. */ -class FrameListColumnPayload extends Component { +class FrameListColumnData extends Component { static get propTypes() { return { item: PropTypes.object.isRequired, @@ -61,4 +61,4 @@ class FrameListColumnPayload extends Component { } } -module.exports = FrameListColumnPayload; +module.exports = FrameListColumnData; diff --git a/devtools/client/netmonitor/src/components/websockets/FrameListColumnTime.js b/devtools/client/netmonitor/src/components/websockets/FrameListColumnTime.js index 908c212c81ae..0f91f0f9c541 100644 --- a/devtools/client/netmonitor/src/components/websockets/FrameListColumnTime.js +++ b/devtools/client/netmonitor/src/components/websockets/FrameListColumnTime.js @@ -29,6 +29,7 @@ class FrameListColumnTime extends Component { // Convert microseconds (DOMHighResTimeStamp) to milliseconds const time = timeStamp / 1000; + const microseconds = (timeStamp % 1000).toString().padStart(3, "0"); return dom.td( { @@ -36,7 +37,9 @@ class FrameListColumnTime extends Component { className: "ws-frames-list-column ws-frames-list-time", title: timeStamp, }, - new Date(time).toLocaleTimeString() + new Date(time).toLocaleTimeString(undefined, { hour12: false }) + + "." + + microseconds ); } } diff --git a/devtools/client/netmonitor/src/components/websockets/FrameListContent.js b/devtools/client/netmonitor/src/components/websockets/FrameListContent.js index c229cfde9845..981305fc3fb9 100644 --- a/devtools/client/netmonitor/src/components/websockets/FrameListContent.js +++ b/devtools/client/netmonitor/src/components/websockets/FrameListContent.js @@ -12,7 +12,7 @@ const PropTypes = require("devtools/client/shared/vendor/react-prop-types"); const { connect, } = require("devtools/client/shared/redux/visibility-handler-connect"); -const { getFramesByChannelId } = require("../../selectors/index"); +const { getDisplayedFrames } = require("../../selectors/index"); const dom = require("devtools/client/shared/vendor/react-dom-factories"); const { table, tbody, div } = dom; @@ -38,7 +38,6 @@ const LEFT_MOUSE_BUTTON = 0; class FrameListContent extends Component { static get propTypes() { return { - channelId: PropTypes.number, connector: PropTypes.object.isRequired, frames: PropTypes.array, selectedFrame: PropTypes.object, @@ -59,7 +58,7 @@ class FrameListContent extends Component { render() { const { frames, selectedFrame, connector } = this.props; - if (!frames) { + if (frames.length === 0) { return div( { className: "empty-notice ws-frame-list-empty-notice" }, FRAMES_EMPTY_TEXT @@ -89,9 +88,9 @@ class FrameListContent extends Component { } module.exports = connect( - (state, props) => ({ + state => ({ selectedFrame: getSelectedFrame(state), - frames: getFramesByChannelId(state, props.channelId), + frames: getDisplayedFrames(state), }), dispatch => ({ selectFrame: item => dispatch(Actions.selectFrame(item)), diff --git a/devtools/client/netmonitor/src/components/websockets/FrameListItem.js b/devtools/client/netmonitor/src/components/websockets/FrameListItem.js index 1591f7b44a26..9bc12e01af98 100644 --- a/devtools/client/netmonitor/src/components/websockets/FrameListItem.js +++ b/devtools/client/netmonitor/src/components/websockets/FrameListItem.js @@ -18,8 +18,8 @@ loader.lazyGetter(this, "FrameListColumnType", function() { loader.lazyGetter(this, "FrameListColumnSize", function() { return createFactory(require("./FrameListColumnSize")); }); -loader.lazyGetter(this, "FrameListColumnPayload", function() { - return createFactory(require("./FrameListColumnPayload")); +loader.lazyGetter(this, "FrameListColumnData", function() { + return createFactory(require("./FrameListColumnData")); }); loader.lazyGetter(this, "FrameListColumnOpCode", function() { return createFactory(require("./FrameListColumnOpCode")); @@ -37,7 +37,7 @@ loader.lazyGetter(this, "FrameListColumnTime", function() { const COLUMN_COMPONENTS = [ { column: "type", ColumnComponent: FrameListColumnType }, { column: "size", ColumnComponent: FrameListColumnSize }, - { column: "payload", ColumnComponent: FrameListColumnPayload }, + { column: "data", ColumnComponent: FrameListColumnData }, { column: "opCode", ColumnComponent: FrameListColumnOpCode }, { column: "maskBit", ColumnComponent: FrameListColumnMaskBit }, { column: "finBit", ColumnComponent: FrameListColumnFinBit }, diff --git a/devtools/client/netmonitor/src/components/websockets/Toolbar.js b/devtools/client/netmonitor/src/components/websockets/Toolbar.js new file mode 100644 index 000000000000..eede5886cad6 --- /dev/null +++ b/devtools/client/netmonitor/src/components/websockets/Toolbar.js @@ -0,0 +1,129 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +const { + Component, + createFactory, +} = require("devtools/client/shared/vendor/react"); +const { + connect, +} = require("devtools/client/shared/redux/visibility-handler-connect"); +const PropTypes = require("devtools/client/shared/vendor/react-prop-types"); +const Actions = require("devtools/client/netmonitor/src/actions/index"); +const { + FILTER_SEARCH_DELAY, +} = require("devtools/client/netmonitor/src/constants"); +const dom = require("devtools/client/shared/vendor/react-dom-factories"); +const { L10N } = require("devtools/client/netmonitor/src/utils/l10n.js"); +const { button, span, div } = dom; + +// Components +const FrameFilterMenu = createFactory(require("./FrameFilterMenu")); +const SearchBox = createFactory( + require("devtools/client/shared/components/SearchBox") +); + +// Localization +const WS_TOOLBAR_CLEAR = L10N.getStr("netmonitor.ws.toolbar.clear"); +const WS_SEARCH_KEY_SHORTCUT = L10N.getStr( + "netmonitor.ws.toolbar.filterFreetext.key" +); +const WS_SEARCH_PLACE_HOLDER = L10N.getStr( + "netmonitor.ws.toolbar.filterFreetext.label" +); + +/** + * WebSocketsPanel toolbar component. + * + * Toolbar contains a set of useful tools that clear the list of + * existing frames as well as filter content. + */ +class Toolbar extends Component { + static get propTypes() { + return { + searchboxRef: PropTypes.object.isRequired, + toggleFrameFilterType: PropTypes.func.isRequired, + clearFrames: PropTypes.func.isRequired, + setFrameFilterText: PropTypes.func.isRequired, + frameFilterType: PropTypes.string.isRequired, + }; + } + + /** + * Render a separator. + */ + renderSeparator() { + return span({ className: "devtools-separator" }); + } + + /** + * Render a clear button. + */ + renderClearButton(clearFrames) { + return button({ + className: + "devtools-button devtools-clear-icon ws-frames-list-clear-button", + title: WS_TOOLBAR_CLEAR, + onClick: () => { + clearFrames(); + }, + }); + } + + /** + * Render the frame filter menu button. + */ + renderFrameFilterMenu() { + const { frameFilterType, toggleFrameFilterType } = this.props; + + return FrameFilterMenu({ + frameFilterType, + toggleFrameFilterType, + }); + } + + /** + * Render filter Searchbox. + */ + renderFilterBox(setFrameFilterText) { + return SearchBox({ + delay: FILTER_SEARCH_DELAY, + keyShortcut: WS_SEARCH_KEY_SHORTCUT, + placeholder: WS_SEARCH_PLACE_HOLDER, + type: "filter", + ref: this.props.searchboxRef, + onChange: setFrameFilterText, + }); + } + + render() { + const { clearFrames, setFrameFilterText } = this.props; + + return div( + { + id: "netmonitor-toolbar-container", + className: "devtools-toolbar devtools-input-toolbar", + }, + this.renderClearButton(clearFrames), + this.renderSeparator(), + this.renderFrameFilterMenu(), + this.renderSeparator(), + this.renderFilterBox(setFrameFilterText) + ); + } +} + +module.exports = connect( + state => ({ + frameFilterType: state.webSockets.frameFilterType, + }), + dispatch => ({ + clearFrames: () => dispatch(Actions.clearFrames()), + toggleFrameFilterType: filter => + dispatch(Actions.toggleFrameFilterType(filter)), + setFrameFilterText: text => dispatch(Actions.setFrameFilterText(text)), + }) +)(Toolbar); diff --git a/devtools/client/netmonitor/src/components/websockets/WebSocketsPanel.js b/devtools/client/netmonitor/src/components/websockets/WebSocketsPanel.js index 6890adca2e54..d485530692f8 100644 --- a/devtools/client/netmonitor/src/components/websockets/WebSocketsPanel.js +++ b/devtools/client/netmonitor/src/components/websockets/WebSocketsPanel.js @@ -7,8 +7,11 @@ const Services = require("Services"); const { Component, + createRef, createFactory, } = require("devtools/client/shared/vendor/react"); +const dom = require("devtools/client/shared/vendor/react-dom-factories"); +const { div } = dom; const PropTypes = require("devtools/client/shared/vendor/react-prop-types"); const { connect, @@ -25,6 +28,7 @@ const SplitBox = createFactory( require("devtools/client/shared/components/splitter/SplitBox") ); const FrameListContent = createFactory(require("./FrameListContent")); +const Toolbar = createFactory(require("./Toolbar")); loader.lazyGetter(this, "FramePayload", function() { return createFactory(require("./FramePayload")); @@ -37,33 +41,44 @@ loader.lazyGetter(this, "FramePayload", function() { class WebSocketsPanel extends Component { static get propTypes() { return { - channelId: PropTypes.number, connector: PropTypes.object.isRequired, selectedFrame: PropTypes.object, frameDetailsOpen: PropTypes.bool.isRequired, openFrameDetailsTab: PropTypes.func.isRequired, selectedFrameVisible: PropTypes.bool.isRequired, + channelId: PropTypes.number, }; } constructor(props) { super(props); + + this.searchboxRef = createRef(); + this.clearFilterText = this.clearFilterText.bind(this); } - componentDidUpdate() { - const { selectedFrameVisible, openFrameDetailsTab } = this.props; + componentDidUpdate(nextProps) { + const { selectedFrameVisible, openFrameDetailsTab, channelId } = this.props; + + // If a new WebSocket connection is selected, clear the filter text + if (channelId !== nextProps.channelId) { + this.clearFilterText(); + } + if (!selectedFrameVisible) { openFrameDetailsTab(false); } } + // Reset the filter text + clearFilterText() { + if (this.searchboxRef) { + this.searchboxRef.current.onClearButtonClick(); + } + } + render() { - const { - frameDetailsOpen, - channelId, - connector, - selectedFrame, - } = this.props; + const { frameDetailsOpen, connector, selectedFrame } = this.props; const initialWidth = Services.prefs.getIntPref( "devtools.netmonitor.ws.payload-preview-width" @@ -72,36 +87,39 @@ class WebSocketsPanel extends Component { "devtools.netmonitor.ws.payload-preview-height" ); - return SplitBox({ - className: "devtools-responsive-container", - initialWidth: initialWidth, - initialHeight: initialHeight, - minSize: "50px", - maxSize: "50%", - splitterSize: frameDetailsOpen ? 1 : 0, - startPanel: FrameListContent({ channelId, connector }), - endPanel: - frameDetailsOpen && - FramePayload({ - connector, - selectedFrame, - }), - endPanelCollapsed: !frameDetailsOpen, - endPanelControl: true, - vert: false, - }); + return div( + { className: "monitor-panel" }, + Toolbar({ + searchboxRef: this.searchboxRef, + }), + SplitBox({ + className: "devtools-responsive-container", + initialWidth: initialWidth, + initialHeight: initialHeight, + minSize: "50px", + maxSize: "50%", + splitterSize: frameDetailsOpen ? 1 : 0, + startPanel: FrameListContent({ connector }), + endPanel: + frameDetailsOpen && + FramePayload({ + connector, + selectedFrame, + }), + endPanelCollapsed: !frameDetailsOpen, + endPanelControl: true, + vert: false, + }) + ); } } module.exports = connect( - (state, props) => ({ - selectedFrame: getSelectedFrame(state), + state => ({ + channelId: state.webSockets.currentChannelId, frameDetailsOpen: state.webSockets.frameDetailsOpen, - selectedFrameVisible: isSelectedFrameVisible( - state, - props.channelId, - getSelectedFrame(state) - ), + selectedFrame: getSelectedFrame(state), + selectedFrameVisible: isSelectedFrameVisible(state), }), dispatch => ({ openFrameDetailsTab: open => dispatch(Actions.openFrameDetails(open)), diff --git a/devtools/client/netmonitor/src/components/websockets/moz.build b/devtools/client/netmonitor/src/components/websockets/moz.build index 0874f3a5d3ed..093acfc06cc5 100644 --- a/devtools/client/netmonitor/src/components/websockets/moz.build +++ b/devtools/client/netmonitor/src/components/websockets/moz.build @@ -3,10 +3,11 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. DevToolsModules( + 'FrameFilterMenu.js', + 'FrameListColumnData.js', 'FrameListColumnFinBit.js', 'FrameListColumnMaskBit.js', 'FrameListColumnOpCode.js', - 'FrameListColumnPayload.js', 'FrameListColumnSize.js', 'FrameListColumnTime.js', 'FrameListColumnType.js', @@ -14,5 +15,6 @@ DevToolsModules( 'FrameListHeader.js', 'FrameListItem.js', 'FramePayload.js', + 'Toolbar.js', 'WebSocketsPanel.js', ) diff --git a/devtools/client/netmonitor/src/constants.js b/devtools/client/netmonitor/src/constants.js index 5a21cb3924e2..86ce34fd6663 100644 --- a/devtools/client/netmonitor/src/constants.js +++ b/devtools/client/netmonitor/src/constants.js @@ -37,6 +37,9 @@ const actionTypes = { WS_ADD_FRAME: "WS_ADD_FRAME", WS_SELECT_FRAME: "WS_SELECT_FRAME", WS_OPEN_FRAME_DETAILS: "WS_OPEN_FRAME_DETAILS", + WS_CLEAR_FRAMES: "WS_CLEAR_FRAMES", + WS_TOGGLE_FRAME_FILTER_TYPE: "WS_TOGGLE_FRAME_FILTER_TYPE", + WS_SET_REQUEST_FILTER_TEXT: "WS_SET_REQUEST_FILTER_TEXT", }; // Descriptions for what this frontend is currently doing. @@ -163,7 +166,7 @@ const UPDATE_PROPS = [ const PANELS = { COOKIES: "cookies", HEADERS: "headers", - WEBSOCKETS: "webSockets", + MESSAGES: "messages", PARAMS: "params", RESPONSE: "response", CACHE: "cache", @@ -325,7 +328,7 @@ const WS_FRAMES_HEADERS = [ name: "size", }, { - name: "payload", + name: "data", }, { name: "opCode", diff --git a/devtools/client/netmonitor/src/reducers/web-sockets.js b/devtools/client/netmonitor/src/reducers/web-sockets.js index 1a712a54ccd3..ad830cddfaf4 100644 --- a/devtools/client/netmonitor/src/reducers/web-sockets.js +++ b/devtools/client/netmonitor/src/reducers/web-sockets.js @@ -5,9 +5,13 @@ "use strict"; const { + SELECT_REQUEST, WS_ADD_FRAME, WS_SELECT_FRAME, WS_OPEN_FRAME_DETAILS, + WS_CLEAR_FRAMES, + WS_TOGGLE_FRAME_FILTER_TYPE, + WS_SET_REQUEST_FILTER_TEXT, } = require("../constants"); /** @@ -18,26 +22,47 @@ function WebSockets() { return { // Map with all requests (key = channelId, value = array of frame objects) frames: new Map(), + frameFilterText: "", + // Default filter type is "all", + frameFilterType: "all", selectedFrame: null, frameDetailsOpen: false, + currentChannelId: null, }; } -// Appending new frame into the map. +/** + * When a network request is selected, + * set the current channelId affiliated with the WebSocket connection. + */ +function setChannelId(state, action) { + return { + ...state, + currentChannelId: action.httpChannelId, + // Default filter text is empty string for a new WebSocket connection + frameFilterText: "", + }; +} + +/** + * Appending new frame into the map. + */ function addFrame(state, action) { + const { httpChannelId } = action; const nextState = { ...state }; const newFrame = { - httpChannelId: action.httpChannelId, + httpChannelId, ...action.data, }; - nextState.frames = mapSet(state.frames, newFrame.httpChannelId, newFrame); - + nextState.frames = mapSet(nextState.frames, newFrame.httpChannelId, newFrame); return nextState; } -// Select specific frame. +/** + * Select specific frame. + */ function selectFrame(state, action) { return { ...state, @@ -46,6 +71,9 @@ function selectFrame(state, action) { }; } +/** + * Shows/Hides the FramePayload component. + */ function openFrameDetails(state, action) { return { ...state, @@ -53,6 +81,45 @@ function openFrameDetails(state, action) { }; } +/** + * Clear WS frames of the request from the state. + */ +function clearFrames(state) { + const nextState = { ...state }; + nextState.frames = new Map(nextState.frames); + nextState.frames.delete(nextState.currentChannelId); + + return { + ...WebSockets(), + // Preserving the Map objects as they might contain state for other channelIds + frames: nextState.frames, + // Preserving the currentChannelId as there would not be another reset of channelId + currentChannelId: nextState.currentChannelId, + frameFilterType: nextState.frameFilterType, + frameFilterText: nextState.frameFilterText, + }; +} + +/** + * Toggle the frame filter type of the WebSocket connection. + */ +function toggleFrameFilterType(state, action) { + return { + ...state, + frameFilterType: action.filter, + }; +} + +/** + * Set the filter text of the current channelId. + */ +function setFrameFilterText(state, action) { + return { + ...state, + frameFilterText: action.text, + }; +} + /** * Append new item into existing map and return new map. */ @@ -73,12 +140,20 @@ function mapSet(map, key, value) { */ function webSockets(state = WebSockets(), action) { switch (action.type) { + case SELECT_REQUEST: + return setChannelId(state, action); case WS_ADD_FRAME: return addFrame(state, action); case WS_SELECT_FRAME: return selectFrame(state, action); case WS_OPEN_FRAME_DETAILS: return openFrameDetails(state, action); + case WS_CLEAR_FRAMES: + return clearFrames(state); + case WS_TOGGLE_FRAME_FILTER_TYPE: + return toggleFrameFilterType(state, action); + case WS_SET_REQUEST_FILTER_TEXT: + return setFrameFilterText(state, action); default: return state; } diff --git a/devtools/client/netmonitor/src/selectors/web-sockets.js b/devtools/client/netmonitor/src/selectors/web-sockets.js index dbee2f66e11b..6c37a58f2255 100644 --- a/devtools/client/netmonitor/src/selectors/web-sockets.js +++ b/devtools/client/netmonitor/src/selectors/web-sockets.js @@ -6,30 +6,52 @@ const { createSelector } = require("devtools/client/shared/vendor/reselect"); -function getFramesByChannelId(state, channelId) { - return state.webSockets.frames.get(channelId); -} +/** + * Returns list of frames that are visible to the user. + * Filtered frames by types and text are factored in. + */ +const getDisplayedFrames = createSelector( + state => state.webSockets, + ({ frames, frameFilterType, frameFilterText, currentChannelId }) => { + if (!currentChannelId || !frames.get(currentChannelId)) { + return []; + } + + const framesArray = frames.get(currentChannelId); + if (frameFilterType === "all" && frameFilterText.length === 0) { + return framesArray; + } + + return framesArray.filter( + frame => + frame.payload.includes(frameFilterText) && + (frameFilterType === "all" || frameFilterType === frame.type) + ); + } +); /** * Checks if the selected frame is visible. * If the selected frame is not visible, the SplitBox component * should not show the FramePayload component. */ -function isSelectedFrameVisible(state, channelId, targetFrame) { - const displayedFrames = getFramesByChannelId(state, channelId); - if (displayedFrames && targetFrame) { - return displayedFrames.some(frame => frame === targetFrame); - } - return false; -} +const isSelectedFrameVisible = createSelector( + state => state.webSockets, + getDisplayedFrames, + ({ selectedFrame }, displayedFrames) => + displayedFrames.some(frame => frame === selectedFrame) +); +/** + * Returns the current selected frame. + */ const getSelectedFrame = createSelector( state => state.webSockets, ({ selectedFrame }) => (selectedFrame ? selectedFrame : undefined) ); module.exports = { - getFramesByChannelId, getSelectedFrame, isSelectedFrameVisible, + getDisplayedFrames, }; diff --git a/devtools/shared/heapsnapshot/HeapSnapshot.cpp b/devtools/shared/heapsnapshot/HeapSnapshot.cpp index 1881dab97d40..f416aacce282 100644 --- a/devtools/shared/heapsnapshot/HeapSnapshot.cpp +++ b/devtools/shared/heapsnapshot/HeapSnapshot.cpp @@ -1287,7 +1287,13 @@ class MOZ_STACK_CLASS HeapSnapshotHandler { if (!first) return true; CoreDumpWriter::EdgePolicy policy; - if (!ShouldIncludeEdge(compartments, origin, edge, &policy)) return true; + if (!ShouldIncludeEdge(compartments, origin, edge, &policy)) { + // Because ShouldIncludeEdge considers the |origin| node as well, we don't + // want to consider this node 'visited' until we write it to the core + // dump. + traversal.doNotMarkReferentAsVisited(); + return true; + } nodeCount++; diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index 4e873326ea41..b1ca0447905b 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -9153,7 +9153,7 @@ nsresult nsDocShell::MaybeHandleSameDocumentNavigation( } else { newURITriggeringPrincipal = aLoadState->TriggeringPrincipal(); newURIPrincipalToInherit = doc->NodePrincipal(); - newURIStoragePrincipalToInherit = doc->EffectiveStoragePrincipal(); + newURIStoragePrincipalToInherit = doc->IntrinsicStoragePrincipal(); newCsp = doc->GetCsp(); } // Pass true for aCloneSHChildren, since we're not @@ -9717,7 +9717,7 @@ nsIPrincipal* nsDocShell::GetInheritedPrincipal( //-- Get the document's principal if (document) { nsIPrincipal* docPrincipal = aConsiderStoragePrincipal - ? document->EffectiveStoragePrincipal() + ? document->IntrinsicStoragePrincipal() : document->NodePrincipal(); // Don't allow loads in typeContent docShells to inherit the system diff --git a/dom/base/Document.h b/dom/base/Document.h index 13d7ee37533a..b2f5441c3099 100644 --- a/dom/base/Document.h +++ b/dom/base/Document.h @@ -559,6 +559,14 @@ class Document : public nsINode, return EffectiveStoragePrincipal(); } + // You should probably not be using this function, since it performs no + // checks to ensure that the intrinsic storage principal should really be + // used here. It is only designed to be used in very specific circumstances, + // such as when inheriting the document/storage principal. + nsIPrincipal* IntrinsicStoragePrincipal() const { + return mIntrinsicStoragePrincipal; + } + // EventTarget void GetEventTargetParent(EventChainPreVisitor& aVisitor) override; EventListenerManager* GetOrCreateListenerManager() override; diff --git a/dom/bindings/test/TestCodeGen.webidl b/dom/bindings/test/TestCodeGen.webidl index 4c353b72c49a..f338b07d432e 100644 --- a/dom/bindings/test/TestCodeGen.webidl +++ b/dom/bindings/test/TestCodeGen.webidl @@ -12,7 +12,7 @@ typedef CustomEventInit TestDictionaryTypedef; interface TestExternalInterface; // We need a pref name that's in StaticPrefList.h here. -[Pref="abc.def"] +[Pref="dom.webidl.test1"] interface TestRenamedInterface { }; @@ -899,63 +899,63 @@ interface TestInterface { void passVariadicThirdArg(DOMString arg1, long arg2, TestInterface... arg3); // Conditionally exposed methods/attributes - [Pref="abc.def"] + [Pref="dom.webidl.test1"] readonly attribute boolean prefable1; - [Pref="abc.def"] + [Pref="dom.webidl.test1"] readonly attribute boolean prefable2; - [Pref="ghi.jkl"] + [Pref="dom.webidl.test2"] readonly attribute boolean prefable3; - [Pref="ghi.jkl"] + [Pref="dom.webidl.test2"] readonly attribute boolean prefable4; - [Pref="abc.def"] + [Pref="dom.webidl.test1"] readonly attribute boolean prefable5; - [Pref="abc.def", Func="nsGenericHTMLElement::LegacyTouchAPIEnabled"] + [Pref="dom.webidl.test1", Func="nsGenericHTMLElement::LegacyTouchAPIEnabled"] readonly attribute boolean prefable6; - [Pref="abc.def", Func="nsGenericHTMLElement::LegacyTouchAPIEnabled"] + [Pref="dom.webidl.test1", Func="nsGenericHTMLElement::LegacyTouchAPIEnabled"] readonly attribute boolean prefable7; - [Pref="ghi.jkl", Func="nsGenericHTMLElement::LegacyTouchAPIEnabled"] + [Pref="dom.webidl.test2", Func="nsGenericHTMLElement::LegacyTouchAPIEnabled"] readonly attribute boolean prefable8; - [Pref="abc.def", Func="nsGenericHTMLElement::LegacyTouchAPIEnabled"] + [Pref="dom.webidl.test1", Func="nsGenericHTMLElement::LegacyTouchAPIEnabled"] readonly attribute boolean prefable9; - [Pref="abc.def"] + [Pref="dom.webidl.test1"] void prefable10(); - [Pref="abc.def", Func="nsGenericHTMLElement::LegacyTouchAPIEnabled"] + [Pref="dom.webidl.test1", Func="nsGenericHTMLElement::LegacyTouchAPIEnabled"] void prefable11(); - [Pref="abc.def", Func="TestFuncControlledMember"] + [Pref="dom.webidl.test1", Func="TestFuncControlledMember"] readonly attribute boolean prefable12; - [Pref="abc.def", Func="nsGenericHTMLElement::LegacyTouchAPIEnabled"] + [Pref="dom.webidl.test1", Func="nsGenericHTMLElement::LegacyTouchAPIEnabled"] void prefable13(); - [Pref="abc.def", Func="TestFuncControlledMember"] + [Pref="dom.webidl.test1", Func="TestFuncControlledMember"] readonly attribute boolean prefable14; [Func="TestFuncControlledMember"] readonly attribute boolean prefable15; [Func="TestFuncControlledMember"] readonly attribute boolean prefable16; - [Pref="abc.def", Func="TestFuncControlledMember"] + [Pref="dom.webidl.test1", Func="TestFuncControlledMember"] void prefable17(); [Func="TestFuncControlledMember"] void prefable18(); [Func="TestFuncControlledMember"] void prefable19(); - [Pref="abc.def", Func="TestFuncControlledMember", ChromeOnly] + [Pref="dom.webidl.test1", Func="TestFuncControlledMember", ChromeOnly] void prefable20(); // Conditionally exposed methods/attributes involving [SecureContext] [SecureContext] readonly attribute boolean conditionalOnSecureContext1; - [SecureContext, Pref="abc.def"] + [SecureContext, Pref="dom.webidl.test1"] readonly attribute boolean conditionalOnSecureContext2; - [SecureContext, Pref="abc.def", Func="nsGenericHTMLElement::LegacyTouchAPIEnabled"] + [SecureContext, Pref="dom.webidl.test1", Func="nsGenericHTMLElement::LegacyTouchAPIEnabled"] readonly attribute boolean conditionalOnSecureContext3; - [SecureContext, Pref="abc.def", Func="TestFuncControlledMember"] + [SecureContext, Pref="dom.webidl.test1", Func="TestFuncControlledMember"] readonly attribute boolean conditionalOnSecureContext4; [SecureContext] void conditionalOnSecureContext5(); - [SecureContext, Pref="abc.def"] + [SecureContext, Pref="dom.webidl.test1"] void conditionalOnSecureContext6(); - [SecureContext, Pref="abc.def", Func="nsGenericHTMLElement::LegacyTouchAPIEnabled"] + [SecureContext, Pref="dom.webidl.test1", Func="nsGenericHTMLElement::LegacyTouchAPIEnabled"] void conditionalOnSecureContext7(); - [SecureContext, Pref="abc.def", Func="TestFuncControlledMember"] + [SecureContext, Pref="dom.webidl.test1", Func="TestFuncControlledMember"] void conditionalOnSecureContext8(); // Miscellania @@ -1221,9 +1221,9 @@ dictionary DictWithConditionalMembers { [ChromeOnly, Func="nsGenericHTMLElement::LegacyTouchAPIEnabled"] long chromeOnlyFuncControlledMember; // We need a pref name that's in StaticPrefList.h here. - [Pref="abc.def"] + [Pref="dom.webidl.test1"] long prefControlledMember; - [Pref="abc.def", ChromeOnly, Func="TestFuncControlledMember"] + [Pref="dom.webidl.test1", ChromeOnly, Func="TestFuncControlledMember"] long chromeOnlyFuncAndPrefControlledMember; }; diff --git a/dom/bindings/test/TestExampleGen.webidl b/dom/bindings/test/TestExampleGen.webidl index 35b9908acbc6..f3f4fff2ffb3 100644 --- a/dom/bindings/test/TestExampleGen.webidl +++ b/dom/bindings/test/TestExampleGen.webidl @@ -705,39 +705,39 @@ interface TestExampleInterface { void passVariadicThirdArg(DOMString arg1, long arg2, TestInterface... arg3); // Conditionally exposed methods/attributes - [Pref="abc.def"] + [Pref="dom.webidl.test1"] readonly attribute boolean prefable1; - [Pref="abc.def"] + [Pref="dom.webidl.test1"] readonly attribute boolean prefable2; - [Pref="ghi.jkl"] + [Pref="dom.webidl.test2"] readonly attribute boolean prefable3; - [Pref="ghi.jkl"] + [Pref="dom.webidl.test2"] readonly attribute boolean prefable4; - [Pref="abc.def"] + [Pref="dom.webidl.test1"] readonly attribute boolean prefable5; - [Pref="abc.def", Func="nsGenericHTMLElement::LegacyTouchAPIEnabled"] + [Pref="dom.webidl.test1", Func="nsGenericHTMLElement::LegacyTouchAPIEnabled"] readonly attribute boolean prefable6; - [Pref="abc.def", Func="nsGenericHTMLElement::LegacyTouchAPIEnabled"] + [Pref="dom.webidl.test1", Func="nsGenericHTMLElement::LegacyTouchAPIEnabled"] readonly attribute boolean prefable7; - [Pref="ghi.jkl", Func="nsGenericHTMLElement::LegacyTouchAPIEnabled"] + [Pref="dom.webidl.test2", Func="nsGenericHTMLElement::LegacyTouchAPIEnabled"] readonly attribute boolean prefable8; - [Pref="abc.def", Func="nsGenericHTMLElement::LegacyTouchAPIEnabled"] + [Pref="dom.webidl.test1", Func="nsGenericHTMLElement::LegacyTouchAPIEnabled"] readonly attribute boolean prefable9; - [Pref="abc.def"] + [Pref="dom.webidl.test1"] void prefable10(); - [Pref="abc.def", Func="nsGenericHTMLElement::LegacyTouchAPIEnabled"] + [Pref="dom.webidl.test1", Func="nsGenericHTMLElement::LegacyTouchAPIEnabled"] void prefable11(); - [Pref="abc.def", Func="TestFuncControlledMember"] + [Pref="dom.webidl.test1", Func="TestFuncControlledMember"] readonly attribute boolean prefable12; - [Pref="abc.def", Func="nsGenericHTMLElement::LegacyTouchAPIEnabled"] + [Pref="dom.webidl.test1", Func="nsGenericHTMLElement::LegacyTouchAPIEnabled"] void prefable13(); - [Pref="abc.def", Func="TestFuncControlledMember"] + [Pref="dom.webidl.test1", Func="TestFuncControlledMember"] readonly attribute boolean prefable14; [Func="TestFuncControlledMember"] readonly attribute boolean prefable15; [Func="TestFuncControlledMember"] readonly attribute boolean prefable16; - [Pref="abc.def", Func="TestFuncControlledMember"] + [Pref="dom.webidl.test1", Func="TestFuncControlledMember"] void prefable17(); [Func="TestFuncControlledMember"] void prefable18(); @@ -747,19 +747,19 @@ interface TestExampleInterface { // Conditionally exposed methods/attributes involving [SecureContext] [SecureContext] readonly attribute boolean conditionalOnSecureContext1; - [SecureContext, Pref="abc.def"] + [SecureContext, Pref="dom.webidl.test1"] readonly attribute boolean conditionalOnSecureContext2; - [SecureContext, Pref="abc.def", Func="nsGenericHTMLElement::LegacyTouchAPIEnabled"] + [SecureContext, Pref="dom.webidl.test1", Func="nsGenericHTMLElement::LegacyTouchAPIEnabled"] readonly attribute boolean conditionalOnSecureContext3; - [SecureContext, Pref="abc.def", Func="TestFuncControlledMember"] + [SecureContext, Pref="dom.webidl.test1", Func="TestFuncControlledMember"] readonly attribute boolean conditionalOnSecureContext4; [SecureContext] void conditionalOnSecureContext5(); - [SecureContext, Pref="abc.def"] + [SecureContext, Pref="dom.webidl.test1"] void conditionalOnSecureContext6(); - [SecureContext, Pref="abc.def", Func="nsGenericHTMLElement::LegacyTouchAPIEnabled"] + [SecureContext, Pref="dom.webidl.test1", Func="nsGenericHTMLElement::LegacyTouchAPIEnabled"] void conditionalOnSecureContext7(); - [SecureContext, Pref="abc.def", Func="TestFuncControlledMember"] + [SecureContext, Pref="dom.webidl.test1", Func="TestFuncControlledMember"] void conditionalOnSecureContext8(); // Miscellania diff --git a/dom/bindings/test/TestJSImplGen.webidl b/dom/bindings/test/TestJSImplGen.webidl index fbd9a3c1c4f1..5b5ddd5f544a 100644 --- a/dom/bindings/test/TestJSImplGen.webidl +++ b/dom/bindings/test/TestJSImplGen.webidl @@ -723,63 +723,63 @@ interface TestJSImplInterface { void passVariadicThirdArg(DOMString arg1, long arg2, TestJSImplInterface... arg3); // Conditionally exposed methods/attributes - [Pref="abc.def"] + [Pref="dom.webidl.test1"] readonly attribute boolean prefable1; - [Pref="abc.def"] + [Pref="dom.webidl.test1"] readonly attribute boolean prefable2; - [Pref="ghi.jkl"] + [Pref="dom.webidl.test2"] readonly attribute boolean prefable3; - [Pref="ghi.jkl"] + [Pref="dom.webidl.test2"] readonly attribute boolean prefable4; - [Pref="abc.def"] + [Pref="dom.webidl.test1"] readonly attribute boolean prefable5; - [Pref="abc.def", Func="nsGenericHTMLElement::LegacyTouchAPIEnabled"] + [Pref="dom.webidl.test1", Func="nsGenericHTMLElement::LegacyTouchAPIEnabled"] readonly attribute boolean prefable6; - [Pref="abc.def", Func="nsGenericHTMLElement::LegacyTouchAPIEnabled"] + [Pref="dom.webidl.test1", Func="nsGenericHTMLElement::LegacyTouchAPIEnabled"] readonly attribute boolean prefable7; - [Pref="ghi.jkl", Func="nsGenericHTMLElement::LegacyTouchAPIEnabled"] + [Pref="dom.webidl.test2", Func="nsGenericHTMLElement::LegacyTouchAPIEnabled"] readonly attribute boolean prefable8; - [Pref="abc.def", Func="nsGenericHTMLElement::LegacyTouchAPIEnabled"] + [Pref="dom.webidl.test1", Func="nsGenericHTMLElement::LegacyTouchAPIEnabled"] readonly attribute boolean prefable9; - [Pref="abc.def"] + [Pref="dom.webidl.test1"] void prefable10(); - [Pref="abc.def", Func="nsGenericHTMLElement::LegacyTouchAPIEnabled"] + [Pref="dom.webidl.test1", Func="nsGenericHTMLElement::LegacyTouchAPIEnabled"] void prefable11(); - [Pref="abc.def", Func="TestFuncControlledMember"] + [Pref="dom.webidl.test1", Func="TestFuncControlledMember"] readonly attribute boolean prefable12; - [Pref="abc.def", Func="nsGenericHTMLElement::LegacyTouchAPIEnabled"] + [Pref="dom.webidl.test1", Func="nsGenericHTMLElement::LegacyTouchAPIEnabled"] void prefable13(); - [Pref="abc.def", Func="TestFuncControlledMember"] + [Pref="dom.webidl.test1", Func="TestFuncControlledMember"] readonly attribute boolean prefable14; [Func="TestFuncControlledMember"] readonly attribute boolean prefable15; [Func="TestFuncControlledMember"] readonly attribute boolean prefable16; - [Pref="abc.def", Func="TestFuncControlledMember"] + [Pref="dom.webidl.test1", Func="TestFuncControlledMember"] void prefable17(); [Func="TestFuncControlledMember"] void prefable18(); [Func="TestFuncControlledMember"] void prefable19(); - [Pref="abc.def", Func="TestFuncControlledMember", ChromeOnly] + [Pref="dom.webidl.test1", Func="TestFuncControlledMember", ChromeOnly] void prefable20(); // Conditionally exposed methods/attributes involving [SecureContext] [SecureContext] readonly attribute boolean conditionalOnSecureContext1; - [SecureContext, Pref="abc.def"] + [SecureContext, Pref="dom.webidl.test1"] readonly attribute boolean conditionalOnSecureContext2; - [SecureContext, Pref="abc.def", Func="nsGenericHTMLElement::LegacyTouchAPIEnabled"] + [SecureContext, Pref="dom.webidl.test1", Func="nsGenericHTMLElement::LegacyTouchAPIEnabled"] readonly attribute boolean conditionalOnSecureContext3; - [SecureContext, Pref="abc.def", Func="TestFuncControlledMember"] + [SecureContext, Pref="dom.webidl.test1", Func="TestFuncControlledMember"] readonly attribute boolean conditionalOnSecureContext4; [SecureContext] void conditionalOnSecureContext5(); - [SecureContext, Pref="abc.def"] + [SecureContext, Pref="dom.webidl.test1"] void conditionalOnSecureContext6(); - [SecureContext, Pref="abc.def", Func="nsGenericHTMLElement::LegacyTouchAPIEnabled"] + [SecureContext, Pref="dom.webidl.test1", Func="nsGenericHTMLElement::LegacyTouchAPIEnabled"] void conditionalOnSecureContext7(); - [SecureContext, Pref="abc.def", Func="TestFuncControlledMember"] + [SecureContext, Pref="dom.webidl.test1", Func="TestFuncControlledMember"] void conditionalOnSecureContext8(); // Miscellania diff --git a/dom/cache/ActorChild.cpp b/dom/cache/ActorChild.cpp index affbe0a11829..08c724ffd3b5 100644 --- a/dom/cache/ActorChild.cpp +++ b/dom/cache/ActorChild.cpp @@ -6,45 +6,45 @@ #include "mozilla/dom/cache/ActorChild.h" -#include "mozilla/dom/cache/CacheWorkerHolder.h" +#include "mozilla/dom/cache/CacheWorkerRef.h" #include "nsThreadUtils.h" namespace mozilla { namespace dom { namespace cache { -void ActorChild::SetWorkerHolder(CacheWorkerHolder* aWorkerHolder) { +void ActorChild::SetWorkerRef(CacheWorkerRef* aWorkerRef) { // Some of the Cache actors can have multiple DOM objects associated with - // them. In this case the workerHolder will be added multiple times. This is - // permitted, but the workerHolder should be the same each time. - if (mWorkerHolder) { - MOZ_DIAGNOSTIC_ASSERT(mWorkerHolder == aWorkerHolder); + // them. In this case the workerRef will be added multiple times. This is + // permitted, but the workerRef should be the same each time. + if (mWorkerRef) { + MOZ_DIAGNOSTIC_ASSERT(mWorkerRef == aWorkerRef); return; } - mWorkerHolder = aWorkerHolder; - if (mWorkerHolder) { - mWorkerHolder->AddActor(this); + mWorkerRef = aWorkerRef; + if (mWorkerRef) { + mWorkerRef->AddActor(this); } } -void ActorChild::RemoveWorkerHolder() { - MOZ_ASSERT_IF(!NS_IsMainThread(), mWorkerHolder); - if (mWorkerHolder) { - mWorkerHolder->RemoveActor(this); - mWorkerHolder = nullptr; +void ActorChild::RemoveWorkerRef() { + MOZ_ASSERT_IF(!NS_IsMainThread(), mWorkerRef); + if (mWorkerRef) { + mWorkerRef->RemoveActor(this); + mWorkerRef = nullptr; } } -CacheWorkerHolder* ActorChild::GetWorkerHolder() const { return mWorkerHolder; } +CacheWorkerRef* ActorChild::GetWorkerRef() const { return mWorkerRef; } -bool ActorChild::WorkerHolderNotified() const { - return mWorkerHolder && mWorkerHolder->Notified(); +bool ActorChild::WorkerRefNotified() const { + return mWorkerRef && mWorkerRef->Notified(); } ActorChild::ActorChild() {} -ActorChild::~ActorChild() { MOZ_DIAGNOSTIC_ASSERT(!mWorkerHolder); } +ActorChild::~ActorChild() { MOZ_DIAGNOSTIC_ASSERT(!mWorkerRef); } } // namespace cache } // namespace dom diff --git a/dom/cache/ActorChild.h b/dom/cache/ActorChild.h index 7bcfe2f41d7d..c3bb3f37617c 100644 --- a/dom/cache/ActorChild.h +++ b/dom/cache/ActorChild.h @@ -13,26 +13,26 @@ namespace mozilla { namespace dom { namespace cache { -class CacheWorkerHolder; +class CacheWorkerRef; class ActorChild { public: virtual void StartDestroy() = 0; - void SetWorkerHolder(CacheWorkerHolder* aWorkerHolder); + void SetWorkerRef(CacheWorkerRef* aWorkerRef); - void RemoveWorkerHolder(); + void RemoveWorkerRef(); - CacheWorkerHolder* GetWorkerHolder() const; + CacheWorkerRef* GetWorkerRef() const; - bool WorkerHolderNotified() const; + bool WorkerRefNotified() const; protected: ActorChild(); ~ActorChild(); private: - RefPtr mWorkerHolder; + RefPtr mWorkerRef; }; } // namespace cache diff --git a/dom/cache/Cache.cpp b/dom/cache/Cache.cpp index cb42e2e08684..446e61042e8e 100644 --- a/dom/cache/Cache.cpp +++ b/dom/cache/Cache.cpp @@ -15,7 +15,7 @@ #include "mozilla/dom/CacheBinding.h" #include "mozilla/dom/cache/AutoUtils.h" #include "mozilla/dom/cache/CacheChild.h" -#include "mozilla/dom/cache/CacheWorkerHolder.h" +#include "mozilla/dom/cache/CacheWorkerRef.h" #include "mozilla/dom/cache/ReadStream.h" #include "mozilla/ErrorResult.h" #include "mozilla/Preferences.h" @@ -96,19 +96,19 @@ static bool IsValidPutResponseStatus(Response& aResponse, } // namespace // Helper class to wait for Add()/AddAll() fetch requests to complete and -// then perform a PutAll() with the responses. This class holds a WorkerHolder +// then perform a PutAll() with the responses. This class holds a WorkerRef // to keep the Worker thread alive. This is mainly to ensure that Add/AddAll // act the same as other Cache operations that directly create a CacheOpChild // actor. class Cache::FetchHandler final : public PromiseNativeHandler { public: - FetchHandler(CacheWorkerHolder* aWorkerHolder, Cache* aCache, + FetchHandler(CacheWorkerRef* aWorkerRef, Cache* aCache, nsTArray>&& aRequestList, Promise* aPromise) - : mWorkerHolder(aWorkerHolder), + : mWorkerRef(aWorkerRef), mCache(aCache), mRequestList(std::move(aRequestList)), mPromise(aPromise) { - MOZ_ASSERT_IF(!NS_IsMainThread(), mWorkerHolder); + MOZ_ASSERT_IF(!NS_IsMainThread(), mWorkerRef); MOZ_DIAGNOSTIC_ASSERT(mCache); MOZ_DIAGNOSTIC_ASSERT(mPromise); } @@ -118,8 +118,8 @@ class Cache::FetchHandler final : public PromiseNativeHandler { NS_ASSERT_OWNINGTHREAD(FetchHandler); // Stop holding the worker alive when we leave this method. - RefPtr workerHolder; - workerHolder.swap(mWorkerHolder); + RefPtr workerRef; + workerRef.swap(mWorkerRef); // Promise::All() passed an array of fetch() Promises should give us // an Array of Response objects. The following code unwraps these @@ -220,7 +220,7 @@ class Cache::FetchHandler final : public PromiseNativeHandler { mPromise->MaybeReject(rv); } - RefPtr mWorkerHolder; + RefPtr mWorkerRef; RefPtr mCache; nsTArray> mRequestList; RefPtr mPromise; @@ -576,7 +576,7 @@ already_AddRefed Cache::AddAll( } RefPtr handler = new FetchHandler( - mActor->GetWorkerHolder(), this, std::move(aRequestList), promise); + mActor->GetWorkerRef(), this, std::move(aRequestList), promise); RefPtr fetchPromise = Promise::All(aGlobal.Context(), fetchList, aRv); diff --git a/dom/cache/CacheChild.cpp b/dom/cache/CacheChild.cpp index ec3c8a836981..35a50cb9012c 100644 --- a/dom/cache/CacheChild.cpp +++ b/dom/cache/CacheChild.cpp @@ -54,7 +54,7 @@ void CacheChild::ExecuteOp(nsIGlobalObject* aGlobal, Promise* aPromise, nsISupports* aParent, const CacheOpArgs& aArgs) { mNumChildActors += 1; MOZ_ALWAYS_TRUE(SendPCacheOpConstructor( - new CacheOpChild(GetWorkerHolder(), aGlobal, aParent, aPromise), aArgs)); + new CacheOpChild(GetWorkerRef(), aGlobal, aParent, aPromise), aArgs)); } void CacheChild::StartDestroyFromListener() { @@ -83,7 +83,7 @@ void CacheChild::StartDestroy() { RefPtr listener = mListener; - // StartDestroy() can get called from either Cache or the WorkerHolder. + // StartDestroy() can get called from either Cache or the WorkerRef. // Theoretically we can get double called if the right race happens. Handle // that by just ignoring the second StartDestroy() call. if (!listener) { @@ -108,7 +108,7 @@ void CacheChild::ActorDestroy(ActorDestroyReason aReason) { MOZ_DIAGNOSTIC_ASSERT(!mListener); } - RemoveWorkerHolder(); + RemoveWorkerRef(); } PCacheOpChild* CacheChild::AllocPCacheOpChild(const CacheOpArgs& aOpArgs) { diff --git a/dom/cache/CacheChild.h b/dom/cache/CacheChild.h index 71df0fa6d160..274d8fff27bb 100644 --- a/dom/cache/CacheChild.h +++ b/dom/cache/CacheChild.h @@ -58,7 +58,7 @@ class CacheChild final : public PCacheChild, public ActorChild { private: // ActorChild methods - // WorkerHolder is trying to destroy due to worker shutdown. + // WorkerRef is trying to destroy due to worker shutdown. virtual void StartDestroy() override; // PCacheChild methods diff --git a/dom/cache/CacheOpChild.cpp b/dom/cache/CacheOpChild.cpp index 73a5e4de3287..bedc280a2828 100644 --- a/dom/cache/CacheOpChild.cpp +++ b/dom/cache/CacheOpChild.cpp @@ -12,7 +12,7 @@ #include "mozilla/dom/cache/Cache.h" #include "mozilla/dom/cache/CacheChild.h" #include "mozilla/dom/cache/CacheStreamControlChild.h" -#include "mozilla/dom/cache/CacheWorkerHolder.h" +#include "mozilla/dom/cache/CacheWorkerRef.h" namespace mozilla { namespace dom { @@ -22,54 +22,53 @@ using mozilla::ipc::PBackgroundChild; namespace { -void AddWorkerHolderToStreamChild(const CacheReadStream& aReadStream, - CacheWorkerHolder* aWorkerHolder) { - MOZ_ASSERT_IF(!NS_IsMainThread(), aWorkerHolder); +void AddWorkerRefToStreamChild(const CacheReadStream& aReadStream, + CacheWorkerRef* aWorkerRef) { + MOZ_ASSERT_IF(!NS_IsMainThread(), aWorkerRef); CacheStreamControlChild* cacheControl = static_cast(aReadStream.controlChild()); if (cacheControl) { - cacheControl->SetWorkerHolder(aWorkerHolder); + cacheControl->SetWorkerRef(aWorkerRef); } } -void AddWorkerHolderToStreamChild(const CacheResponse& aResponse, - CacheWorkerHolder* aWorkerHolder) { - MOZ_ASSERT_IF(!NS_IsMainThread(), aWorkerHolder); +void AddWorkerRefToStreamChild(const CacheResponse& aResponse, + CacheWorkerRef* aWorkerRef) { + MOZ_ASSERT_IF(!NS_IsMainThread(), aWorkerRef); if (aResponse.body().isNothing()) { return; } - AddWorkerHolderToStreamChild(aResponse.body().ref(), aWorkerHolder); + AddWorkerRefToStreamChild(aResponse.body().ref(), aWorkerRef); } -void AddWorkerHolderToStreamChild(const CacheRequest& aRequest, - CacheWorkerHolder* aWorkerHolder) { - MOZ_ASSERT_IF(!NS_IsMainThread(), aWorkerHolder); +void AddWorkerRefToStreamChild(const CacheRequest& aRequest, + CacheWorkerRef* aWorkerRef) { + MOZ_ASSERT_IF(!NS_IsMainThread(), aWorkerRef); if (aRequest.body().isNothing()) { return; } - AddWorkerHolderToStreamChild(aRequest.body().ref(), aWorkerHolder); + AddWorkerRefToStreamChild(aRequest.body().ref(), aWorkerRef); } } // namespace -CacheOpChild::CacheOpChild(CacheWorkerHolder* aWorkerHolder, - nsIGlobalObject* aGlobal, nsISupports* aParent, - Promise* aPromise) +CacheOpChild::CacheOpChild(CacheWorkerRef* aWorkerRef, nsIGlobalObject* aGlobal, + nsISupports* aParent, Promise* aPromise) : mGlobal(aGlobal), mParent(aParent), mPromise(aPromise) { MOZ_DIAGNOSTIC_ASSERT(mGlobal); MOZ_DIAGNOSTIC_ASSERT(mParent); MOZ_DIAGNOSTIC_ASSERT(mPromise); - MOZ_ASSERT_IF(!NS_IsMainThread(), aWorkerHolder); + MOZ_ASSERT_IF(!NS_IsMainThread(), aWorkerRef); - RefPtr workerHolder = CacheWorkerHolder::PreferBehavior( - aWorkerHolder, CacheWorkerHolder::PreventIdleShutdownStart); + RefPtr workerRef = CacheWorkerRef::PreferBehavior( + aWorkerRef, CacheWorkerRef::eStrongWorkerRef); - SetWorkerHolder(workerHolder); + SetWorkerRef(workerRef); } CacheOpChild::~CacheOpChild() { @@ -87,7 +86,7 @@ void CacheOpChild::ActorDestroy(ActorDestroyReason aReason) { mPromise = nullptr; } - RemoveWorkerHolder(); + RemoveWorkerRef(); } mozilla::ipc::IPCResult CacheOpChild::Recv__delete__( @@ -147,11 +146,10 @@ mozilla::ipc::IPCResult CacheOpChild::Recv__delete__( break; } - RefPtr workerHolder = - CacheWorkerHolder::PreferBehavior( - GetWorkerHolder(), CacheWorkerHolder::AllowIdleShutdownStart); + RefPtr workerRef = CacheWorkerRef::PreferBehavior( + GetWorkerRef(), CacheWorkerRef::eIPCWorkerRef); - actor->SetWorkerHolder(workerHolder); + actor->SetWorkerRef(workerRef); RefPtr cache = new Cache(mGlobal, actor, result.ns()); mPromise->MaybeResolve(cache); break; @@ -176,7 +174,7 @@ mozilla::ipc::IPCResult CacheOpChild::Recv__delete__( void CacheOpChild::StartDestroy() { NS_ASSERT_OWNINGTHREAD(CacheOpChild); - // Do not cancel on-going operations when WorkerHolder calls this. Instead, + // Do not cancel on-going operations when WorkerRef calls this. Instead, // keep the Worker alive until we are done. } @@ -200,7 +198,7 @@ void CacheOpChild::HandleResponse(const Maybe& aMaybeResponse) { const CacheResponse& cacheResponse = aMaybeResponse.ref(); - AddWorkerHolderToStreamChild(cacheResponse, GetWorkerHolder()); + AddWorkerRefToStreamChild(cacheResponse, GetWorkerRef()); RefPtr response = ToResponse(cacheResponse); mPromise->MaybeResolve(response); @@ -212,7 +210,7 @@ void CacheOpChild::HandleResponseList( responses.SetCapacity(aResponseList.Length()); for (uint32_t i = 0; i < aResponseList.Length(); ++i) { - AddWorkerHolderToStreamChild(aResponseList[i], GetWorkerHolder()); + AddWorkerRefToStreamChild(aResponseList[i], GetWorkerRef()); responses.AppendElement(ToResponse(aResponseList[i])); } @@ -225,7 +223,7 @@ void CacheOpChild::HandleRequestList( requests.SetCapacity(aRequestList.Length()); for (uint32_t i = 0; i < aRequestList.Length(); ++i) { - AddWorkerHolderToStreamChild(aRequestList[i], GetWorkerHolder()); + AddWorkerRefToStreamChild(aRequestList[i], GetWorkerRef()); requests.AppendElement(ToRequest(aRequestList[i])); } diff --git a/dom/cache/CacheOpChild.h b/dom/cache/CacheOpChild.h index e692ec6a4b94..fd6928cf61fe 100644 --- a/dom/cache/CacheOpChild.h +++ b/dom/cache/CacheOpChild.h @@ -31,7 +31,7 @@ class CacheOpChild final : public PCacheOpChild, private: // This class must be constructed by CacheChild or CacheStorageChild using // their ExecuteOp() factory method. - CacheOpChild(CacheWorkerHolder* aWorkerHolder, nsIGlobalObject* aGlobal, + CacheOpChild(CacheWorkerRef* aWorkerRef, nsIGlobalObject* aGlobal, nsISupports* aParent, Promise* aPromise); ~CacheOpChild(); diff --git a/dom/cache/CacheStorage.cpp b/dom/cache/CacheStorage.cpp index 3912a99ae639..81cc73c58f49 100644 --- a/dom/cache/CacheStorage.cpp +++ b/dom/cache/CacheStorage.cpp @@ -16,7 +16,7 @@ #include "mozilla/dom/cache/Cache.h" #include "mozilla/dom/cache/CacheChild.h" #include "mozilla/dom/cache/CacheStorageChild.h" -#include "mozilla/dom/cache/CacheWorkerHolder.h" +#include "mozilla/dom/cache/CacheWorkerRef.h" #include "mozilla/dom/cache/PCacheChild.h" #include "mozilla/dom/cache/ReadStream.h" #include "mozilla/dom/cache/TypeUtils.h" @@ -189,9 +189,9 @@ already_AddRefed CacheStorage::CreateOnWorker( return ref.forget(); } - RefPtr workerHolder = CacheWorkerHolder::Create( - aWorkerPrivate, CacheWorkerHolder::AllowIdleShutdownStart); - if (!workerHolder) { + RefPtr workerRef = + CacheWorkerRef::Create(aWorkerPrivate, CacheWorkerRef::eIPCWorkerRef); + if (!workerRef) { NS_WARNING("Worker thread is shutting down."); aRv.Throw(NS_ERROR_FAILURE); return nullptr; @@ -230,7 +230,7 @@ already_AddRefed CacheStorage::CreateOnWorker( } RefPtr ref = - new CacheStorage(aNamespace, aGlobal, principalInfo, workerHolder); + new CacheStorage(aNamespace, aGlobal, principalInfo, workerRef); return ref.forget(); } @@ -268,7 +268,7 @@ bool CacheStorage::DefineCaches(JSContext* aCx, JS::Handle aGlobal) { CacheStorage::CacheStorage(Namespace aNamespace, nsIGlobalObject* aGlobal, const PrincipalInfo& aPrincipalInfo, - CacheWorkerHolder* aWorkerHolder) + CacheWorkerRef* aWorkerRef) : mNamespace(aNamespace), mGlobal(aGlobal), mPrincipalInfo(MakeUnique(aPrincipalInfo)), @@ -284,10 +284,10 @@ CacheStorage::CacheStorage(Namespace aNamespace, nsIGlobalObject* aGlobal, return; } - // WorkerHolder ownership is passed to the CacheStorageChild actor and any - // actors it may create. The WorkerHolder will keep the worker thread alive + // WorkerRef ownership is passed to the CacheStorageChild actor and any + // actors it may create. The WorkerRef will keep the worker thread alive // until the actors can gracefully shutdown. - CacheStorageChild* newActor = new CacheStorageChild(this, aWorkerHolder); + CacheStorageChild* newActor = new CacheStorageChild(this, aWorkerRef); PCacheStorageChild* constructedActor = actor->SendPCacheStorageConstructor( newActor, mNamespace, *mPrincipalInfo); diff --git a/dom/cache/CacheStorage.h b/dom/cache/CacheStorage.h index c564aed4718f..f776590395e9 100644 --- a/dom/cache/CacheStorage.h +++ b/dom/cache/CacheStorage.h @@ -34,7 +34,7 @@ class WorkerPrivate; namespace cache { class CacheStorageChild; -class CacheWorkerHolder; +class CacheWorkerRef; class CacheStorage final : public nsISupports, public nsWrapperCache, @@ -86,7 +86,7 @@ class CacheStorage final : public nsISupports, private: CacheStorage(Namespace aNamespace, nsIGlobalObject* aGlobal, const mozilla::ipc::PrincipalInfo& aPrincipalInfo, - CacheWorkerHolder* aWorkerHolder); + CacheWorkerRef* aWorkerRef); explicit CacheStorage(nsresult aFailureResult); ~CacheStorage(); diff --git a/dom/cache/CacheStorageChild.cpp b/dom/cache/CacheStorageChild.cpp index 287c7562c76b..b35bddb89e12 100644 --- a/dom/cache/CacheStorageChild.cpp +++ b/dom/cache/CacheStorageChild.cpp @@ -19,12 +19,12 @@ namespace cache { void DeallocPCacheStorageChild(PCacheStorageChild* aActor) { delete aActor; } CacheStorageChild::CacheStorageChild(CacheStorage* aListener, - CacheWorkerHolder* aWorkerHolder) + CacheWorkerRef* aWorkerRef) : mListener(aListener), mNumChildActors(0), mDelayedDestroy(false) { MOZ_COUNT_CTOR(cache::CacheStorageChild); MOZ_DIAGNOSTIC_ASSERT(mListener); - SetWorkerHolder(aWorkerHolder); + SetWorkerRef(aWorkerRef); } CacheStorageChild::~CacheStorageChild() { @@ -44,7 +44,7 @@ void CacheStorageChild::ExecuteOp(nsIGlobalObject* aGlobal, Promise* aPromise, const CacheOpArgs& aArgs) { mNumChildActors += 1; Unused << SendPCacheOpConstructor( - new CacheOpChild(GetWorkerHolder(), aGlobal, aParent, aPromise), aArgs); + new CacheOpChild(GetWorkerRef(), aGlobal, aParent, aPromise), aArgs); } void CacheStorageChild::StartDestroyFromListener() { @@ -73,7 +73,7 @@ void CacheStorageChild::StartDestroy() { RefPtr listener = mListener; // StartDestroy() can get called from either CacheStorage or the - // CacheWorkerHolder. + // CacheWorkerRef. // Theoretically we can get double called if the right race happens. Handle // that by just ignoring the second StartDestroy() call. if (!listener) { @@ -98,7 +98,7 @@ void CacheStorageChild::ActorDestroy(ActorDestroyReason aReason) { MOZ_DIAGNOSTIC_ASSERT(!mListener); } - RemoveWorkerHolder(); + RemoveWorkerRef(); } PCacheOpChild* CacheStorageChild::AllocPCacheOpChild( diff --git a/dom/cache/CacheStorageChild.h b/dom/cache/CacheStorageChild.h index cc20b6484940..0aac33bb8d9a 100644 --- a/dom/cache/CacheStorageChild.h +++ b/dom/cache/CacheStorageChild.h @@ -22,14 +22,14 @@ namespace cache { class CacheOpArgs; class CacheStorage; -class CacheWorkerHolder; +class CacheWorkerRef; class PCacheChild; class CacheStorageChild final : public PCacheStorageChild, public ActorChild { friend class PCacheStorageChild; public: - CacheStorageChild(CacheStorage* aListener, CacheWorkerHolder* aWorkerHolder); + CacheStorageChild(CacheStorage* aListener, CacheWorkerRef* aWorkerRef); ~CacheStorageChild(); // Must be called by the associated CacheStorage listener in its @@ -47,7 +47,7 @@ class CacheStorageChild final : public PCacheStorageChild, public ActorChild { private: // ActorChild methods - // CacheWorkerHolder is trying to destroy due to worker shutdown. + // CacheWorkerRef is trying to destroy due to worker shutdown. virtual void StartDestroy() override; // PCacheStorageChild methods diff --git a/dom/cache/CacheStreamControlChild.cpp b/dom/cache/CacheStreamControlChild.cpp index 3051c4eaac83..e34e90992b64 100644 --- a/dom/cache/CacheStreamControlChild.cpp +++ b/dom/cache/CacheStreamControlChild.cpp @@ -9,7 +9,7 @@ #include "mozilla/Unused.h" #include "mozilla/dom/cache/ActorUtils.h" #include "mozilla/dom/cache/CacheTypes.h" -#include "mozilla/dom/cache/CacheWorkerHolder.h" +#include "mozilla/dom/cache/CacheWorkerRef.h" #include "mozilla/dom/cache/ReadStream.h" #include "mozilla/ipc/FileDescriptorSetChild.h" #include "mozilla/ipc/IPCStreamUtils.h" @@ -50,7 +50,7 @@ CacheStreamControlChild::~CacheStreamControlChild() { void CacheStreamControlChild::StartDestroy() { NS_ASSERT_OWNINGTHREAD(CacheStreamControlChild); // This can get called twice under some circumstances. For example, if the - // actor is added to a CacheWorkerHolder that has already been notified and + // actor is added to a CacheWorkerRef that has already been notified and // the Cache actor has no mListener. if (mDestroyStarted) { return; @@ -110,7 +110,7 @@ void CacheStreamControlChild::OpenStream(const nsID& aId, // rejection here in many cases, we must handle the case where the // MozPromise resolve runnable is already in the event queue when the // worker wants to shut down. - RefPtr holder = GetWorkerHolder(); + RefPtr holder = GetWorkerRef(); SendOpenStream(aId)->Then( GetCurrentThreadSerialEventTarget(), __func__, @@ -145,7 +145,7 @@ void CacheStreamControlChild::AssertOwningThread() { void CacheStreamControlChild::ActorDestroy(ActorDestroyReason aReason) { NS_ASSERT_OWNINGTHREAD(CacheStreamControlChild); CloseAllReadStreamsWithoutReporting(); - RemoveWorkerHolder(); + RemoveWorkerRef(); } mozilla::ipc::IPCResult CacheStreamControlChild::RecvClose(const nsID& aId) { diff --git a/dom/cache/CacheWorkerHolder.cpp b/dom/cache/CacheWorkerHolder.cpp deleted file mode 100644 index 0743261f60f6..000000000000 --- a/dom/cache/CacheWorkerHolder.cpp +++ /dev/null @@ -1,111 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "mozilla/dom/cache/CacheWorkerHolder.h" - -#include "mozilla/dom/cache/ActorChild.h" -#include "mozilla/dom/WorkerPrivate.h" - -namespace mozilla { -namespace dom { -namespace cache { - -// static -already_AddRefed CacheWorkerHolder::Create( - WorkerPrivate* aWorkerPrivate, Behavior aBehavior) { - MOZ_DIAGNOSTIC_ASSERT(aWorkerPrivate); - - RefPtr workerHolder = new CacheWorkerHolder(aBehavior); - if (NS_WARN_IF(!workerHolder->HoldWorker(aWorkerPrivate, Canceling))) { - return nullptr; - } - - return workerHolder.forget(); -} - -// static -already_AddRefed CacheWorkerHolder::PreferBehavior( - CacheWorkerHolder* aCurrentHolder, Behavior aBehavior) { - if (!aCurrentHolder) { - return nullptr; - } - - RefPtr orig = aCurrentHolder; - if (orig->GetBehavior() == aBehavior) { - return orig.forget(); - } - - RefPtr replace = Create(orig->mWorkerPrivate, aBehavior); - if (!replace) { - return orig.forget(); - } - - return replace.forget(); -} - -void CacheWorkerHolder::AddActor(ActorChild* aActor) { - NS_ASSERT_OWNINGTHREAD(CacheWorkerHolder); - MOZ_DIAGNOSTIC_ASSERT(aActor); - MOZ_ASSERT(!mActorList.Contains(aActor)); - - mActorList.AppendElement(aActor); - - // Allow an actor to be added after we've entered the Notifying case. We - // can't stop the actor creation from racing with out destruction of the - // other actors and we need to wait for this extra one to close as well. - // Signal it should destroy itself right away. - if (mNotified) { - aActor->StartDestroy(); - } -} - -void CacheWorkerHolder::RemoveActor(ActorChild* aActor) { - NS_ASSERT_OWNINGTHREAD(CacheWorkerHolder); - MOZ_DIAGNOSTIC_ASSERT(aActor); - -#if defined(RELEASE_OR_BETA) - mActorList.RemoveElement(aActor); -#else - MOZ_DIAGNOSTIC_ASSERT(mActorList.RemoveElement(aActor)); -#endif - - MOZ_ASSERT(!mActorList.Contains(aActor)); -} - -bool CacheWorkerHolder::Notified() const { return mNotified; } - -bool CacheWorkerHolder::Notify(WorkerStatus aStatus) { - NS_ASSERT_OWNINGTHREAD(CacheWorkerHolder); - - // When the service worker thread is stopped we will get Canceling, - // but nothing higher than that. We must shut things down at Canceling. - if (aStatus < Canceling || mNotified) { - return true; - } - - mNotified = true; - - // Start the asynchronous destruction of our actors. These will call back - // into RemoveActor() once the actor is destroyed. - for (uint32_t i = 0; i < mActorList.Length(); ++i) { - MOZ_DIAGNOSTIC_ASSERT(mActorList[i]); - mActorList[i]->StartDestroy(); - } - - return true; -} - -CacheWorkerHolder::CacheWorkerHolder(Behavior aBehavior) - : WorkerHolder("CacheWorkerHolder", aBehavior), mNotified(false) {} - -CacheWorkerHolder::~CacheWorkerHolder() { - NS_ASSERT_OWNINGTHREAD(CacheWorkerHolder); - MOZ_DIAGNOSTIC_ASSERT(mActorList.IsEmpty()); -} - -} // namespace cache -} // namespace dom -} // namespace mozilla diff --git a/dom/cache/CacheWorkerHolder.h b/dom/cache/CacheWorkerHolder.h deleted file mode 100644 index 377a76ee00dd..000000000000 --- a/dom/cache/CacheWorkerHolder.h +++ /dev/null @@ -1,54 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_dom_cache_CacheWorkerHolder_h -#define mozilla_dom_cache_CacheWorkerHolder_h - -#include "nsISupportsImpl.h" -#include "nsTArray.h" -#include "mozilla/dom/WorkerHolder.h" - -namespace mozilla { - -class WorkerPrivate; - -namespace dom { -namespace cache { - -class ActorChild; - -class CacheWorkerHolder final : public WorkerHolder { - public: - static already_AddRefed Create( - WorkerPrivate* aWorkerPrivate, Behavior aBehavior); - - static already_AddRefed PreferBehavior( - CacheWorkerHolder* aCurrentHolder, Behavior aBehavior); - - void AddActor(ActorChild* aActor); - void RemoveActor(ActorChild* aActor); - - bool Notified() const; - - // WorkerHolder methods - virtual bool Notify(WorkerStatus aStatus) override; - - private: - explicit CacheWorkerHolder(Behavior aBehavior); - ~CacheWorkerHolder(); - - nsTArray mActorList; - bool mNotified; - - public: - NS_INLINE_DECL_REFCOUNTING(mozilla::dom::cache::CacheWorkerHolder) -}; - -} // namespace cache -} // namespace dom -} // namespace mozilla - -#endif // mozilla_dom_cache_CacheWorkerHolder_h diff --git a/dom/cache/CacheWorkerRef.cpp b/dom/cache/CacheWorkerRef.cpp new file mode 100644 index 000000000000..b6921c9f0ceb --- /dev/null +++ b/dom/cache/CacheWorkerRef.cpp @@ -0,0 +1,130 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "mozilla/dom/cache/CacheWorkerRef.h" + +#include "mozilla/dom/cache/ActorChild.h" +#include "mozilla/dom/WorkerPrivate.h" +#include "mozilla/dom/WorkerRef.h" + +namespace mozilla { +namespace dom { +namespace cache { + +// static +already_AddRefed CacheWorkerRef::Create( + WorkerPrivate* aWorkerPrivate, Behavior aBehavior) { + MOZ_DIAGNOSTIC_ASSERT(aWorkerPrivate); + + RefPtr workerRef = new CacheWorkerRef(aBehavior); + if (aBehavior == eStrongWorkerRef) { + workerRef->mStrongWorkerRef = + StrongWorkerRef::Create(aWorkerPrivate, "CacheWorkerRef-Strong", + [workerRef] { workerRef->Notify(); }); + } else { + MOZ_ASSERT(aBehavior == eIPCWorkerRef); + workerRef->mIPCWorkerRef = + IPCWorkerRef::Create(aWorkerPrivate, "CacheWorkerRef-IPC", + [workerRef] { workerRef->Notify(); }); + } + + if (NS_WARN_IF(!workerRef->mIPCWorkerRef && !workerRef->mStrongWorkerRef)) { + return nullptr; + } + + return workerRef.forget(); +} + +// static +already_AddRefed CacheWorkerRef::PreferBehavior( + CacheWorkerRef* aCurrentRef, Behavior aBehavior) { + if (!aCurrentRef) { + return nullptr; + } + + RefPtr orig = aCurrentRef; + if (orig->mBehavior == aBehavior) { + return orig.forget(); + } + + WorkerPrivate* workerPrivate = nullptr; + if (orig->mBehavior == eStrongWorkerRef) { + workerPrivate = orig->mStrongWorkerRef->Private(); + } else { + MOZ_ASSERT(orig->mBehavior == eIPCWorkerRef); + workerPrivate = orig->mIPCWorkerRef->Private(); + } + + MOZ_ASSERT(workerPrivate); + + RefPtr replace = Create(workerPrivate, aBehavior); + if (!replace) { + return orig.forget(); + } + + return replace.forget(); +} + +void CacheWorkerRef::AddActor(ActorChild* aActor) { + NS_ASSERT_OWNINGTHREAD(CacheWorkerRef); + MOZ_DIAGNOSTIC_ASSERT(aActor); + MOZ_ASSERT(!mActorList.Contains(aActor)); + + mActorList.AppendElement(aActor); + + // Allow an actor to be added after we've entered the Notifying case. We + // can't stop the actor creation from racing with out destruction of the + // other actors and we need to wait for this extra one to close as well. + // Signal it should destroy itself right away. + if (mNotified) { + aActor->StartDestroy(); + } +} + +void CacheWorkerRef::RemoveActor(ActorChild* aActor) { + NS_ASSERT_OWNINGTHREAD(CacheWorkerRef); + MOZ_DIAGNOSTIC_ASSERT(aActor); + +#if defined(RELEASE_OR_BETA) + mActorList.RemoveElement(aActor); +#else + MOZ_DIAGNOSTIC_ASSERT(mActorList.RemoveElement(aActor)); +#endif + + MOZ_ASSERT(!mActorList.Contains(aActor)); + + if (mActorList.IsEmpty()) { + mStrongWorkerRef = nullptr; + mIPCWorkerRef = nullptr; + } +} + +bool CacheWorkerRef::Notified() const { return mNotified; } + +void CacheWorkerRef::Notify() { + NS_ASSERT_OWNINGTHREAD(CacheWorkerRef); + + mNotified = true; + + // Start the asynchronous destruction of our actors. These will call back + // into RemoveActor() once the actor is destroyed. + for (uint32_t i = 0; i < mActorList.Length(); ++i) { + MOZ_DIAGNOSTIC_ASSERT(mActorList[i]); + mActorList[i]->StartDestroy(); + } +} + +CacheWorkerRef::CacheWorkerRef(Behavior aBehavior) + : mBehavior(aBehavior), mNotified(false) {} + +CacheWorkerRef::~CacheWorkerRef() { + NS_ASSERT_OWNINGTHREAD(CacheWorkerRef); + MOZ_DIAGNOSTIC_ASSERT(mActorList.IsEmpty()); +} + +} // namespace cache +} // namespace dom +} // namespace mozilla diff --git a/dom/cache/CacheWorkerRef.h b/dom/cache/CacheWorkerRef.h new file mode 100644 index 000000000000..ef01114bc92a --- /dev/null +++ b/dom/cache/CacheWorkerRef.h @@ -0,0 +1,64 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_dom_cache_CacheWorkerRef_h +#define mozilla_dom_cache_CacheWorkerRef_h + +#include "nsISupportsImpl.h" +#include "nsTArray.h" + +namespace mozilla { +namespace dom { + +class IPCWorkerRef; +class StrongWorkerRef; +class WorkerPrivate; + +namespace cache { + +class ActorChild; + +class CacheWorkerRef final { + public: + enum Behavior { + eStrongWorkerRef, + eIPCWorkerRef, + }; + + static already_AddRefed Create(WorkerPrivate* aWorkerPrivate, + Behavior aBehavior); + + static already_AddRefed PreferBehavior( + CacheWorkerRef* aCurrentRef, Behavior aBehavior); + + void AddActor(ActorChild* aActor); + void RemoveActor(ActorChild* aActor); + + bool Notified() const; + + private: + explicit CacheWorkerRef(Behavior aBehavior); + ~CacheWorkerRef(); + + void Notify(); + + nsTArray mActorList; + + Behavior mBehavior; + bool mNotified; + + RefPtr mStrongWorkerRef; + RefPtr mIPCWorkerRef; + + public: + NS_INLINE_DECL_REFCOUNTING(mozilla::dom::cache::CacheWorkerRef) +}; + +} // namespace cache +} // namespace dom +} // namespace mozilla + +#endif // mozilla_dom_cache_CacheWorkerRef_h diff --git a/dom/cache/moz.build b/dom/cache/moz.build index c00d939f3835..c1b124bc05cb 100644 --- a/dom/cache/moz.build +++ b/dom/cache/moz.build @@ -23,7 +23,7 @@ EXPORTS.mozilla.dom.cache += [ 'CacheStorageParent.h', 'CacheStreamControlChild.h', 'CacheStreamControlParent.h', - 'CacheWorkerHolder.h', + 'CacheWorkerRef.h', 'Connection.h', 'Context.h', 'DBAction.h', @@ -56,7 +56,7 @@ UNIFIED_SOURCES += [ 'CacheStorageParent.cpp', 'CacheStreamControlChild.cpp', 'CacheStreamControlParent.cpp', - 'CacheWorkerHolder.cpp', + 'CacheWorkerRef.cpp', 'Connection.cpp', 'Context.cpp', 'DBAction.cpp', diff --git a/dom/canvas/CanvasImageCache.cpp b/dom/canvas/CanvasImageCache.cpp index efb1c7c5449f..7b79378b52d4 100644 --- a/dom/canvas/CanvasImageCache.cpp +++ b/dom/canvas/CanvasImageCache.cpp @@ -42,7 +42,8 @@ struct ImageCacheEntryData { : mImage(aOther.mImage), mCanvas(aOther.mCanvas), mSourceSurface(aOther.mSourceSurface), - mSize(aOther.mSize) {} + mSize(aOther.mSize), + mIntrinsicSize(aOther.mIntrinsicSize) {} explicit ImageCacheEntryData(const ImageCacheKey& aKey) : mImage(aKey.mImage), mCanvas(aKey.mCanvas) {} @@ -55,6 +56,7 @@ struct ImageCacheEntryData { // Value RefPtr mSourceSurface; IntSize mSize; + IntSize mIntrinsicSize; nsExpirationState mState; }; @@ -257,7 +259,8 @@ static already_AddRefed GetImageContainer(dom::Element* aImage) { void CanvasImageCache::NotifyDrawImage(Element* aImage, HTMLCanvasElement* aCanvas, SourceSurface* aSource, - const IntSize& aSize) { + const IntSize& aSize, + const IntSize& aIntrinsicSize) { if (!gImageCache) { gImageCache = new ImageCache(); nsContentUtils::RegisterShutdownObserver( @@ -284,6 +287,7 @@ void CanvasImageCache::NotifyDrawImage(Element* aImage, gImageCache->AddObject(entry->mData); entry->mData->mSourceSurface = aSource; entry->mData->mSize = aSize; + entry->mData->mIntrinsicSize = aIntrinsicSize; gImageCache->mTotal += entry->mData->SizeInBytes(); AllCanvasImageCacheEntry* allEntry = @@ -321,7 +325,8 @@ SourceSurface* CanvasImageCache::LookupAllCanvas(Element* aImage) { SourceSurface* CanvasImageCache::LookupCanvas(Element* aImage, HTMLCanvasElement* aCanvas, - IntSize* aSizeOut) { + IntSize* aSizeOut, + IntSize* aIntrinsicSizeOut) { if (!gImageCache) { return nullptr; } @@ -341,6 +346,7 @@ SourceSurface* CanvasImageCache::LookupCanvas(Element* aImage, gImageCache->MarkUsed(entry->mData); *aSizeOut = entry->mData->mSize; + *aIntrinsicSizeOut = entry->mData->mIntrinsicSize; return entry->mData->mSourceSurface; } diff --git a/dom/canvas/CanvasImageCache.h b/dom/canvas/CanvasImageCache.h index 6648d5ad33f8..eb619abcaffd 100644 --- a/dom/canvas/CanvasImageCache.h +++ b/dom/canvas/CanvasImageCache.h @@ -29,12 +29,13 @@ class CanvasImageCache { /** * Notify that image element aImage was drawn to aCanvas element * using the first frame of aRequest's image. The data for the surface is - * in aSurface, and the image size is in aSize. + * in aSurface, and the image size is in aSize. aIntrinsicSize is the size + * the surface is intended to be rendered at. */ static void NotifyDrawImage(dom::Element* aImage, dom::HTMLCanvasElement* aCanvas, - SourceSurface* aSource, - const gfx::IntSize& aSize); + SourceSurface* aSource, const gfx::IntSize& aSize, + const gfx::IntSize& aIntrinsicSize); /** * Check whether aImage has recently been drawn any canvas. If we return @@ -48,7 +49,8 @@ class CanvasImageCache { */ static SourceSurface* LookupCanvas(dom::Element* aImage, dom::HTMLCanvasElement* aCanvas, - gfx::IntSize* aSizeOut); + gfx::IntSize* aSizeOut, + gfx::IntSize* aIntrinsicSizeOut); }; } // namespace mozilla diff --git a/dom/canvas/CanvasRenderingContext2D.cpp b/dom/canvas/CanvasRenderingContext2D.cpp index a79055caabf3..283db35eb1e5 100644 --- a/dom/canvas/CanvasRenderingContext2D.cpp +++ b/dom/canvas/CanvasRenderingContext2D.cpp @@ -4288,7 +4288,7 @@ CanvasRenderingContext2D::CachedSurfaceFromElement(Element* aElement) { res.mCORSUsed = corsmode != imgIRequest::CORS_NONE; } - res.mSize = res.mSourceSurface->GetSize(); + res.mSize = res.mIntrinsicSize = res.mSourceSurface->GetSize(); res.mPrincipal = principal.forget(); res.mImageRequest = imgRequest.forget(); res.mIsWriteOnly = CheckWriteOnlySecurity(res.mCORSUsed, res.mPrincipal, @@ -4331,6 +4331,7 @@ void CanvasRenderingContext2D::DrawImage(const CanvasImageSource& aImage, RefPtr srcSurf; gfx::IntSize imgSize; + gfx::IntSize intrinsicImgSize; Element* element = nullptr; @@ -4363,7 +4364,8 @@ void CanvasRenderingContext2D::DrawImage(const CanvasImageSource& aImage, SetWriteOnly(); } - imgSize = gfx::IntSize(imageBitmap.Width(), imageBitmap.Height()); + imgSize = intrinsicImgSize = + gfx::IntSize(imageBitmap.Width(), imageBitmap.Height()); } else { if (aImage.IsHTMLImageElement()) { HTMLImageElement* img = &aImage.GetAsHTMLImageElement(); @@ -4378,7 +4380,8 @@ void CanvasRenderingContext2D::DrawImage(const CanvasImageSource& aImage, element = video; } - srcSurf = CanvasImageCache::LookupCanvas(element, mCanvasElement, &imgSize); + srcSurf = CanvasImageCache::LookupCanvas(element, mCanvasElement, &imgSize, + &intrinsicImgSize); } nsLayoutUtils::DirectDrawInfo drawInfo; @@ -4408,18 +4411,7 @@ void CanvasRenderingContext2D::DrawImage(const CanvasImageSource& aImage, } imgSize = res.mSize; - - // Scale sw/sh based on aspect ratio - if (aImage.IsHTMLVideoElement()) { - HTMLVideoElement* video = &aImage.GetAsHTMLVideoElement(); - int32_t displayWidth = video->VideoWidth(); - int32_t displayHeight = video->VideoHeight(); - if (displayWidth == 0 || displayHeight == 0) { - return; - } - aSw *= (double)imgSize.width / (double)displayWidth; - aSh *= (double)imgSize.height / (double)displayHeight; - } + intrinsicImgSize = res.mIntrinsicSize; if (mCanvasElement) { CanvasUtils::DoDrawImageSecurityCheck(mCanvasElement, res.mPrincipal, @@ -4429,7 +4421,8 @@ void CanvasRenderingContext2D::DrawImage(const CanvasImageSource& aImage, if (res.mSourceSurface) { if (res.mImageRequest) { CanvasImageCache::NotifyDrawImage(element, mCanvasElement, - res.mSourceSurface, imgSize); + res.mSourceSurface, imgSize, + intrinsicImgSize); } srcSurf = res.mSourceSurface; } else { @@ -4439,8 +4432,10 @@ void CanvasRenderingContext2D::DrawImage(const CanvasImageSource& aImage, if (aOptional_argc == 0) { aSx = aSy = 0.0; - aDw = aSw = (double)imgSize.width; - aDh = aSh = (double)imgSize.height; + aSw = (double)imgSize.width; + aSh = (double)imgSize.height; + aDw = (double)intrinsicImgSize.width; + aDh = (double)intrinsicImgSize.height; } else if (aOptional_argc == 2) { aSx = aSy = 0.0; aSw = (double)imgSize.width; diff --git a/dom/canvas/WebGLContext.cpp b/dom/canvas/WebGLContext.cpp index 308daf371b4b..56cc7ef7453a 100644 --- a/dom/canvas/WebGLContext.cpp +++ b/dom/canvas/WebGLContext.cpp @@ -455,7 +455,7 @@ bool WebGLContext::CreateAndInitGL( } // WebGL2 is separately blocked: - if (IsWebGL2()) { + if (IsWebGL2() && !forceEnabled) { const nsCOMPtr gfxInfo = services::GetGfxInfo(); const auto feature = nsIGfxInfo::FEATURE_WEBGL2; diff --git a/dom/clients/api/ClientDOMUtil.h b/dom/clients/api/ClientDOMUtil.h index ef7831881d91..5181b061b26a 100644 --- a/dom/clients/api/ClientDOMUtil.h +++ b/dom/clients/api/ClientDOMUtil.h @@ -9,7 +9,6 @@ #include "mozilla/dom/ClientIPCTypes.h" #include "mozilla/dom/ClientOpPromise.h" #include "mozilla/dom/DOMMozPromiseRequestHolder.h" -#include "mozilla/dom/WorkerHolderToken.h" #include "mozilla/dom/WorkerPrivate.h" class nsIGlobalObject; diff --git a/dom/clients/manager/ClientManager.cpp b/dom/clients/manager/ClientManager.cpp index c62ca4f0474e..e2db3e030372 100644 --- a/dom/clients/manager/ClientManager.cpp +++ b/dom/clients/manager/ClientManager.cpp @@ -11,7 +11,6 @@ #include "ClientManagerOpChild.h" #include "ClientPrefs.h" #include "ClientSource.h" -#include "mozilla/dom/WorkerHolderToken.h" #include "mozilla/dom/WorkerPrivate.h" #include "mozilla/ipc/BackgroundChild.h" #include "mozilla/ipc/PBackgroundChild.h" @@ -54,27 +53,12 @@ ClientManager::ClientManager() { return; } - RefPtr workerHolderToken; - if (!NS_IsMainThread()) { - WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate(); - MOZ_DIAGNOSTIC_ASSERT(workerPrivate); - - // Note, it would be nice to replace this with a WorkerRef, but - // currently there is no WorkerRef option that matches what we - // need here. We need something like a StrongWorkerRef that will - // let us keep the worker alive until our actor is destroyed, but - // we also need to use AllowIdleShutdownStart like WeakWorkerRef. - // We need AllowIdleShutdownStart since every worker thread will - // have a ClientManager to support creating its ClientSource. - workerHolderToken = WorkerHolderToken::Create( - workerPrivate, Canceling, WorkerHolderToken::AllowIdleShutdownStart); - if (NS_WARN_IF(!workerHolderToken)) { - Shutdown(); - return; - } + ClientManagerChild* actor = ClientManagerChild::Create(); + if (NS_WARN_IF(!actor)) { + Shutdown(); + return; } - ClientManagerChild* actor = new ClientManagerChild(workerHolderToken); PClientManagerChild* sentActor = parentActor->SendPClientManagerConstructor(actor); if (NS_WARN_IF(!sentActor)) { diff --git a/dom/clients/manager/ClientManagerChild.cpp b/dom/clients/manager/ClientManagerChild.cpp index aa6bdc245907..d9320c43d626 100644 --- a/dom/clients/manager/ClientManagerChild.cpp +++ b/dom/clients/manager/ClientManagerChild.cpp @@ -11,14 +11,13 @@ #include "ClientNavigateOpChild.h" #include "ClientSourceChild.h" +#include "mozilla/dom/WorkerRef.h" + namespace mozilla { namespace dom { void ClientManagerChild::ActorDestroy(ActorDestroyReason aReason) { - if (mWorkerHolderToken) { - mWorkerHolderToken->RemoveListener(this); - mWorkerHolderToken = nullptr; - } + mIPCWorkerRef = nullptr; if (mManager) { mManager->RevokeActor(this); @@ -81,19 +80,33 @@ bool ClientManagerChild::DeallocPClientSourceChild(PClientSourceChild* aActor) { return true; } -void ClientManagerChild::WorkerShuttingDown() { MaybeStartTeardown(); } +// static +ClientManagerChild* ClientManagerChild::Create() { + ClientManagerChild* actor = new ClientManagerChild(); -ClientManagerChild::ClientManagerChild(WorkerHolderToken* aWorkerHolderToken) - : mManager(nullptr), - mWorkerHolderToken(aWorkerHolderToken), - mTeardownStarted(false) { - MOZ_ASSERT_IF(!NS_IsMainThread(), mWorkerHolderToken); + if (!NS_IsMainThread()) { + WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate(); + MOZ_DIAGNOSTIC_ASSERT(workerPrivate); - if (mWorkerHolderToken) { - mWorkerHolderToken->AddListener(this); + RefPtr> helper = + new IPCWorkerRefHelper(actor); + + actor->mIPCWorkerRef = IPCWorkerRef::Create( + workerPrivate, "ClientManagerChild", + [helper] { helper->Actor()->MaybeStartTeardown(); }); + + if (NS_WARN_IF(!actor->mIPCWorkerRef)) { + delete actor; + return nullptr; + } } + + return actor; } +ClientManagerChild::ClientManagerChild() + : mManager(nullptr), mTeardownStarted(false) {} + void ClientManagerChild::SetOwner(ClientThing* aThing) { MOZ_DIAGNOSTIC_ASSERT(aThing); MOZ_DIAGNOSTIC_ASSERT(!mManager); @@ -115,10 +128,10 @@ void ClientManagerChild::MaybeStartTeardown() { } WorkerPrivate* ClientManagerChild::GetWorkerPrivate() const { - if (!mWorkerHolderToken) { + if (!mIPCWorkerRef) { return nullptr; } - return mWorkerHolderToken->GetWorkerPrivate(); + return mIPCWorkerRef->Private(); } } // namespace dom diff --git a/dom/clients/manager/ClientManagerChild.h b/dom/clients/manager/ClientManagerChild.h index 597dae5e1a69..79e2a9d8f545 100644 --- a/dom/clients/manager/ClientManagerChild.h +++ b/dom/clients/manager/ClientManagerChild.h @@ -8,20 +8,21 @@ #include "ClientThing.h" #include "mozilla/dom/PClientManagerChild.h" -#include "mozilla/dom/WorkerHolderToken.h" namespace mozilla { namespace dom { +class IPCWorkerRef; class WorkerPrivate; -class ClientManagerChild final : public PClientManagerChild, - public WorkerHolderToken::Listener { +class ClientManagerChild final : public PClientManagerChild { ClientThing* mManager; - RefPtr mWorkerHolderToken; + RefPtr mIPCWorkerRef; bool mTeardownStarted; + ClientManagerChild(); + // PClientManagerChild interface void ActorDestroy(ActorDestroyReason aReason) override; @@ -49,11 +50,8 @@ class ClientManagerChild final : public PClientManagerChild, bool DeallocPClientSourceChild(PClientSourceChild* aActor) override; - // WorkerHolderToken::Listener interface - void WorkerShuttingDown() override; - public: - explicit ClientManagerChild(WorkerHolderToken* aWorkerHolderToken); + static ClientManagerChild* Create(); void SetOwner(ClientThing* aThing); diff --git a/dom/indexedDB/IDBTransaction.h b/dom/indexedDB/IDBTransaction.h index 39dcaedd1735..80a90922b360 100644 --- a/dom/indexedDB/IDBTransaction.h +++ b/dom/indexedDB/IDBTransaction.h @@ -46,9 +46,6 @@ class IDBTransaction final : public DOMEventTargetHelper, public nsIRunnable { friend class indexedDB::BackgroundCursorChild; friend class indexedDB::BackgroundRequestChild; - class WorkerHolder; - friend class WorkerHolder; - public: enum Mode { READ_ONLY = 0, diff --git a/dom/media/GraphDriver.cpp b/dom/media/GraphDriver.cpp index ba9b4e16dbb0..4748fbaf7e01 100644 --- a/dom/media/GraphDriver.cpp +++ b/dom/media/GraphDriver.cpp @@ -1132,6 +1132,17 @@ void AudioCallbackDriver::CompleteAudioContextOperations( } } +TimeDuration AudioCallbackDriver::AudioOutputLatency() { + uint32_t latency_frames; + int rv = cubeb_stream_get_latency(mAudioStream, &latency_frames); + if (rv || mSampleRate == 0) { + return TimeDuration::FromSeconds(0.0); + } + + return TimeDuration::FromSeconds(static_cast(latency_frames) / + mSampleRate); +} + void AudioCallbackDriver::FallbackToSystemClockDriver() { MOZ_ASSERT(!ThreadRunning()); GraphImpl()->GetMonitor().AssertCurrentThreadOwns(); diff --git a/dom/media/GraphDriver.h b/dom/media/GraphDriver.h index 34b23c7a6f76..1be917d207d5 100644 --- a/dom/media/GraphDriver.h +++ b/dom/media/GraphDriver.h @@ -433,6 +433,9 @@ class AudioCallbackDriver : public GraphDriver, void CompleteAudioContextOperations(AsyncCubebOperation aOperation); + // Returns the output latency for the current audio output stream. + TimeDuration AudioOutputLatency(); + private: /* Remove Mixer callbacks when switching */ void RemoveMixerCallback(); diff --git a/dom/media/MediaManager.cpp b/dom/media/MediaManager.cpp index 74699e054bc6..014536fb59b4 100644 --- a/dom/media/MediaManager.cpp +++ b/dom/media/MediaManager.cpp @@ -2289,10 +2289,17 @@ static void ReduceConstraint( } // Keep mediaSource, ignore all other constraints. - auto& c = aConstraint.GetAsMediaTrackConstraints(); - MOZ_DIAGNOSTIC_ASSERT(c.mMediaSource.WasPassed()); - nsString mediaSource = c.mMediaSource.Value(); - aConstraint.SetAsMediaTrackConstraints().mMediaSource.Construct(mediaSource); + Maybe mediaSource; + if (aConstraint.GetAsMediaTrackConstraints().mMediaSource.WasPassed()) { + mediaSource = + Some(aConstraint.GetAsMediaTrackConstraints().mMediaSource.Value()); + } + if (mediaSource) { + aConstraint.SetAsMediaTrackConstraints().mMediaSource.Value() = + *mediaSource; + } else { + aConstraint.SetAsMediaTrackConstraints(); + } } /** diff --git a/dom/media/MediaStreamGraph.cpp b/dom/media/MediaStreamGraph.cpp index ab2dcb3f2fa8..674a67ac6e5b 100644 --- a/dom/media/MediaStreamGraph.cpp +++ b/dom/media/MediaStreamGraph.cpp @@ -957,6 +957,10 @@ void MediaStreamGraphImpl::DeviceChanged() { MediaStreamGraphImpl* mGraphImpl; }; + // Reset the latency, it will get fetched again next time it's queried. + MOZ_ASSERT(NS_IsMainThread()); + mAudioOutputLatency = 0.0; + AppendMessage(MakeUnique(this)); } @@ -3192,7 +3196,8 @@ MediaStreamGraphImpl::MediaStreamGraphImpl(GraphDriverType aDriverRequested, mCanRunMessagesSynchronously(false) #endif , - mMainThreadGraphTime(0, "MediaStreamGraphImpl::mMainThreadGraphTime") { + mMainThreadGraphTime(0, "MediaStreamGraphImpl::mMainThreadGraphTime"), + mAudioOutputLatency(0.0) { if (mRealtime) { if (aDriverRequested == AUDIO_THREAD_DRIVER) { // Always start with zero input channels, and no particular preferences @@ -3796,6 +3801,29 @@ void MediaStreamGraph::ApplyAudioContextOperation( aDestinationStream, aStreams, aOperation, aPromise, aFlags)); } +double MediaStreamGraph::AudioOutputLatency() { + return static_cast(this)->AudioOutputLatency(); +} + +double MediaStreamGraphImpl::AudioOutputLatency() { + MOZ_ASSERT(NS_IsMainThread()); + if (mAudioOutputLatency != 0.0) { + return mAudioOutputLatency; + } + MonitorAutoLock lock(mMonitor); + if (CurrentDriver()->AsAudioCallbackDriver()) { + mAudioOutputLatency = CurrentDriver() + ->AsAudioCallbackDriver() + ->AudioOutputLatency() + .ToSeconds(); + } else { + // Failure mode: return 0.0 if running on a normal thread. + mAudioOutputLatency = 0.0; + } + + return mAudioOutputLatency; +} + bool MediaStreamGraph::IsNonRealtime() const { return !static_cast(this)->mRealtime; } diff --git a/dom/media/MediaStreamGraph.h b/dom/media/MediaStreamGraph.h index a35032ccbb05..7df158683b0c 100644 --- a/dom/media/MediaStreamGraph.h +++ b/dom/media/MediaStreamGraph.h @@ -1272,6 +1272,8 @@ class MediaStreamGraph { */ TrackRate GraphRate() const { return mSampleRate; } + double AudioOutputLatency(); + void RegisterCaptureStreamForWindow(uint64_t aWindowId, ProcessedMediaStream* aCaptureStream); void UnregisterCaptureStreamForWindow(uint64_t aWindowId); diff --git a/dom/media/MediaStreamGraphImpl.h b/dom/media/MediaStreamGraphImpl.h index 0e17d6230daa..b2cd22b9a688 100644 --- a/dom/media/MediaStreamGraphImpl.h +++ b/dom/media/MediaStreamGraphImpl.h @@ -453,6 +453,8 @@ class MediaStreamGraphImpl : public MediaStreamGraph, uint32_t AudioOutputChannelCount() const { return mOutputChannels; } + double AudioOutputLatency(); + /** * The audio input channel count for a MediaStreamGraph is the max of all the * channel counts requested by the listeners. The max channel count is @@ -950,6 +952,12 @@ class MediaStreamGraphImpl : public MediaStreamGraph, * Read by stable state runnable on main thread. Protected by mMonitor. */ GraphTime mNextMainThreadGraphTime = 0; + + /** + * Cached audio output latency, in seconds. Main thread only. This is reset + * whenever the audio device running this MediaStreamGraph changes. + */ + double mAudioOutputLatency; }; } // namespace mozilla diff --git a/dom/media/webaudio/AudioContext.cpp b/dom/media/webaudio/AudioContext.cpp index 1398b11904e7..8907032e5d9a 100644 --- a/dom/media/webaudio/AudioContext.cpp +++ b/dom/media/webaudio/AudioContext.cpp @@ -36,6 +36,7 @@ #include "mozilla/dom/OscillatorNodeBinding.h" #include "mozilla/dom/PannerNodeBinding.h" #include "mozilla/dom/PeriodicWaveBinding.h" +#include "mozilla/dom/Performance.h" #include "mozilla/dom/Promise.h" #include "mozilla/dom/StereoPannerNodeBinding.h" #include "mozilla/dom/WaveShaperNodeBinding.h" @@ -523,6 +524,48 @@ AudioListener* AudioContext::Listener() { return mListener; } +double AudioContext::OutputLatency() { + // When reduceFingerprinting is enabled, return a latency figure that is + // fixed, but plausible for the platform. + double latency_s = 0.0; + if (nsRFPService::IsResistFingerprintingEnabled()) { +#ifdef XP_MACOSX + latency_s = 512. / mSampleRate; +#elif MOZ_WIDGET_ANDROID + latency_s = 0.020; +#elif XP_WIN + latency_s = 0.04; +#else // Catchall for other OSes, including Linux. + latency_s = 0.025; +#endif + } else { + return Graph()->AudioOutputLatency(); + } + return latency_s; +} + +void AudioContext::GetOutputTimestamp(AudioTimestamp& aTimeStamp) { + if (!Destination()) { + aTimeStamp.mContextTime.Construct(0.0); + aTimeStamp.mPerformanceTime.Construct(0.0); + return; + } + + // The currentTime currently being output is the currentTime minus the audio + // output latency. The resolution of CurrentTime() is already reduced. + aTimeStamp.mContextTime.Construct( + std::max(0.0, CurrentTime() - OutputLatency())); + nsPIDOMWindowInner* parent = GetParentObject(); + Performance* perf = parent ? parent->GetPerformance() : nullptr; + if (perf) { + // perf->Now() already has reduced resolution here, no need to do it again. + aTimeStamp.mPerformanceTime.Construct( + std::max(0., perf->Now() - (OutputLatency() * 1000.))); + } else { + aTimeStamp.mPerformanceTime.Construct(0.0); + } +} + Worklet* AudioContext::GetAudioWorklet(ErrorResult& aRv) { if (!mWorklet) { mWorklet = AudioWorkletImpl::CreateWorklet(this, aRv); @@ -530,7 +573,6 @@ Worklet* AudioContext::GetAudioWorklet(ErrorResult& aRv) { return mWorklet; } - bool AudioContext::IsRunning() const { return mAudioContextState == AudioContextState::Running; } diff --git a/dom/media/webaudio/AudioContext.h b/dom/media/webaudio/AudioContext.h index 47124eb76374..a4858a74841b 100644 --- a/dom/media/webaudio/AudioContext.h +++ b/dom/media/webaudio/AudioContext.h @@ -9,6 +9,7 @@ #include "AudioParamDescriptorMap.h" #include "mozilla/dom/OfflineAudioContextBinding.h" +#include "mozilla/dom/AudioContextBinding.h" #include "MediaBufferDecoder.h" #include "mozilla/Attributes.h" #include "mozilla/DOMEventTargetHelper.h" @@ -192,6 +193,16 @@ class AudioContext final : public DOMEventTargetHelper, AudioContextState State() const { return mAudioContextState; } + double BaseLatency() const { + // Gecko does not do any buffering between rendering the audio and sending + // it to the audio subsystem. + return 0.0; + } + + double OutputLatency(); + + void GetOutputTimestamp(AudioTimestamp& aTimeStamp); + Worklet* GetAudioWorklet(ErrorResult& aRv); bool IsRunning() const; diff --git a/dom/media/webaudio/MediaElementAudioSourceNode.cpp b/dom/media/webaudio/MediaElementAudioSourceNode.cpp index e90124fc3874..11a0e50de2c4 100644 --- a/dom/media/webaudio/MediaElementAudioSourceNode.cpp +++ b/dom/media/webaudio/MediaElementAudioSourceNode.cpp @@ -13,8 +13,31 @@ namespace mozilla { namespace dom { -MediaElementAudioSourceNode::MediaElementAudioSourceNode(AudioContext* aContext) - : MediaStreamAudioSourceNode(aContext, TrackChangeBehavior::FollowChanges) { +NS_IMPL_CYCLE_COLLECTION_CLASS(MediaElementAudioSourceNode) + +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(MediaElementAudioSourceNode) + tmp->Destroy(); + NS_IMPL_CYCLE_COLLECTION_UNLINK(mElement) +NS_IMPL_CYCLE_COLLECTION_UNLINK_END_INHERITED(AudioNode) + +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(MediaElementAudioSourceNode, + MediaStreamAudioSourceNode) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mElement) +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MediaElementAudioSourceNode) +NS_INTERFACE_MAP_END_INHERITING(MediaStreamAudioSourceNode) + +NS_IMPL_ADDREF_INHERITED(MediaElementAudioSourceNode, + MediaStreamAudioSourceNode) +NS_IMPL_RELEASE_INHERITED(MediaElementAudioSourceNode, + MediaStreamAudioSourceNode) + +MediaElementAudioSourceNode::MediaElementAudioSourceNode( + AudioContext* aContext, HTMLMediaElement* aElement) + : MediaStreamAudioSourceNode(aContext, TrackChangeBehavior::FollowChanges), + mElement(aElement) { + MOZ_ASSERT(aElement); } /* static */ @@ -28,7 +51,7 @@ MediaElementAudioSourceNode::Create( } RefPtr node = - new MediaElementAudioSourceNode(&aAudioContext); + new MediaElementAudioSourceNode(&aAudioContext, aOptions.mMediaElement); RefPtr stream = aOptions.mMediaElement->CaptureAudio( aRv, aAudioContext.Destination()->Stream()->Graph()); @@ -71,5 +94,9 @@ void MediaElementAudioSourceNode::Destroy() { MediaStreamAudioSourceNode::Destroy(); } +HTMLMediaElement* MediaElementAudioSourceNode::MediaElement() { + return mElement; +} + } // namespace dom } // namespace mozilla diff --git a/dom/media/webaudio/MediaElementAudioSourceNode.h b/dom/media/webaudio/MediaElementAudioSourceNode.h index adf8673ca689..37d4b36d1dd5 100644 --- a/dom/media/webaudio/MediaElementAudioSourceNode.h +++ b/dom/media/webaudio/MediaElementAudioSourceNode.h @@ -17,6 +17,9 @@ struct MediaElementAudioSourceOptions; class MediaElementAudioSourceNode final : public MediaStreamAudioSourceNode { public: + NS_DECL_ISUPPORTS_INHERITED + NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(MediaElementAudioSourceNode, + MediaStreamAudioSourceNode) static already_AddRefed Create( AudioContext& aAudioContext, const MediaElementAudioSourceOptions& aOptions, ErrorResult& aRv); @@ -42,8 +45,12 @@ class MediaElementAudioSourceNode final : public MediaStreamAudioSourceNode { return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf); } + HTMLMediaElement* MediaElement(); + private: - explicit MediaElementAudioSourceNode(AudioContext* aContext); + explicit MediaElementAudioSourceNode(AudioContext* aContext, + HTMLMediaElement* aElement); + ~MediaElementAudioSourceNode() = default; void Destroy() override; @@ -52,6 +59,8 @@ class MediaElementAudioSourceNode final : public MediaStreamAudioSourceNode { void ListenForAllowedToPlay(const MediaElementAudioSourceOptions& aOptions); MozPromiseRequestHolder mAllowedToPlayRequest; + + RefPtr mElement; }; } // namespace dom diff --git a/dom/media/webaudio/MediaStreamAudioSourceNode.h b/dom/media/webaudio/MediaStreamAudioSourceNode.h index 585bb6ca2233..014ef27f272a 100644 --- a/dom/media/webaudio/MediaStreamAudioSourceNode.h +++ b/dom/media/webaudio/MediaStreamAudioSourceNode.h @@ -65,6 +65,8 @@ class MediaStreamAudioSourceNode uint16_t NumberOfInputs() const override { return 0; } + DOMMediaStream* GetMediaStream() { return mInputStream; } + const char* NodeType() const override { return "MediaStreamAudioSourceNode"; } virtual const char* CrossOriginErrorString() const { diff --git a/dom/notification/Notification.cpp b/dom/notification/Notification.cpp index 2d17c7e2c288..6fb15e48e648 100644 --- a/dom/notification/Notification.cpp +++ b/dom/notification/Notification.cpp @@ -997,7 +997,7 @@ Notification::~Notification() { mData.setUndefined(); mozilla::DropJSObjects(this); AssertIsOnTargetThread(); - MOZ_ASSERT(!mWorkerHolder); + MOZ_ASSERT(!mWorkerRef); MOZ_ASSERT(!mTempRef); } @@ -2054,10 +2054,10 @@ void Notification::InitFromBase64(const nsAString& aData, ErrorResult& aRv) { bool Notification::AddRefObject() { AssertIsOnTargetThread(); - MOZ_ASSERT_IF(mWorkerPrivate && !mWorkerHolder, mTaskCount == 0); - MOZ_ASSERT_IF(mWorkerPrivate && mWorkerHolder, mTaskCount > 0); - if (mWorkerPrivate && !mWorkerHolder) { - if (!RegisterWorkerHolder()) { + MOZ_ASSERT_IF(mWorkerPrivate && !mWorkerRef, mTaskCount == 0); + MOZ_ASSERT_IF(mWorkerPrivate && mWorkerRef, mTaskCount > 0); + if (mWorkerPrivate && !mWorkerRef) { + if (!CreateWorkerRef()) { return false; } } @@ -2069,21 +2069,16 @@ bool Notification::AddRefObject() { void Notification::ReleaseObject() { AssertIsOnTargetThread(); MOZ_ASSERT(mTaskCount > 0); - MOZ_ASSERT_IF(mWorkerPrivate, mWorkerHolder); + MOZ_ASSERT_IF(mWorkerPrivate, mWorkerRef); --mTaskCount; if (mWorkerPrivate && mTaskCount == 0) { - UnregisterWorkerHolder(); + MOZ_ASSERT(mWorkerRef); + mWorkerRef = nullptr; } Release(); } -NotificationWorkerHolder::NotificationWorkerHolder(Notification* aNotification) - : WorkerHolder("NotificationWorkerHolder"), mNotification(aNotification) { - MOZ_ASSERT(mNotification->mWorkerPrivate); - mNotification->mWorkerPrivate->AssertIsOnWorkerThread(); -} - /* * Called from the worker, runs on main thread, blocks worker. * @@ -2116,66 +2111,57 @@ class CloseNotificationRunnable final : public WorkerMainThreadRunnable { bool HadObserver() { return mHadObserver; } }; -bool NotificationWorkerHolder::Notify(WorkerStatus aStatus) { - if (aStatus >= Canceling) { - // CloseNotificationRunnable blocks the worker by pushing a sync event loop - // on the stack. Meanwhile, WorkerControlRunnables dispatched to the worker - // can still continue running. One of these is - // ReleaseNotificationControlRunnable that releases the notification, - // invalidating the notification and this feature. We hold this reference to - // keep the notification valid until we are done with it. - // - // An example of when the control runnable could get dispatched to the - // worker is if a Notification is created and the worker is immediately - // closed, but there is no permission to show it so that the main thread - // immediately drops the NotificationRef. In this case, this function blocks - // on the main thread, but the main thread dispatches the control runnable, - // invalidating mNotification. - RefPtr kungFuDeathGrip = mNotification; - - // Dispatched to main thread, blocks on closing the Notification. - RefPtr r = - new CloseNotificationRunnable(kungFuDeathGrip); - ErrorResult rv; - r->Dispatch(Killing, rv); - // XXXbz I'm told throwing and returning false from here is pointless (and - // also that doing sync stuff from here is really weird), so I guess we just - // suppress the exception on rv, if any. - rv.SuppressException(); - - // Only call ReleaseObject() to match the observer's NotificationRef - // ownership (since CloseNotificationRunnable asked the observer to drop the - // reference to the notification). - if (r->HadObserver()) { - kungFuDeathGrip->ReleaseObject(); - } - - // From this point we cannot touch properties of this feature because - // ReleaseObject() may have led to the notification going away and the - // notification owns this feature! - } - return true; -} - -bool Notification::RegisterWorkerHolder() { +bool Notification::CreateWorkerRef() { MOZ_ASSERT(mWorkerPrivate); mWorkerPrivate->AssertIsOnWorkerThread(); - MOZ_ASSERT(!mWorkerHolder); - mWorkerHolder = MakeUnique(this); - if (NS_WARN_IF(!mWorkerHolder->HoldWorker(mWorkerPrivate, Canceling))) { + MOZ_ASSERT(!mWorkerRef); + + RefPtr self = this; + mWorkerRef = + StrongWorkerRef::Create(mWorkerPrivate, "Notification", [self]() { + // CloseNotificationRunnable blocks the worker by pushing a sync event + // loop on the stack. Meanwhile, WorkerControlRunnables dispatched to + // the worker can still continue running. One of these is + // ReleaseNotificationControlRunnable that releases the notification, + // invalidating the notification and this feature. We hold this + // reference to keep the notification valid until we are done with it. + // + // An example of when the control runnable could get dispatched to the + // worker is if a Notification is created and the worker is immediately + // closed, but there is no permission to show it so that the main thread + // immediately drops the NotificationRef. In this case, this function + // blocks on the main thread, but the main thread dispatches the control + // runnable, invalidating mNotification. + + // Dispatched to main thread, blocks on closing the Notification. + RefPtr r = + new CloseNotificationRunnable(self); + ErrorResult rv; + r->Dispatch(Killing, rv); + // XXXbz I'm told throwing and returning false from here is pointless + // (and also that doing sync stuff from here is really weird), so I + // guess we just suppress the exception on rv, if any. + rv.SuppressException(); + + // Only call ReleaseObject() to match the observer's NotificationRef + // ownership (since CloseNotificationRunnable asked the observer to drop + // the reference to the notification). + if (r->HadObserver()) { + self->ReleaseObject(); + } + + // From this point we cannot touch properties of this feature because + // ReleaseObject() may have led to the notification going away and the + // notification owns this feature! + }); + + if (NS_WARN_IF(!mWorkerRef)) { return false; } return true; } -void Notification::UnregisterWorkerHolder() { - MOZ_ASSERT(mWorkerPrivate); - mWorkerPrivate->AssertIsOnWorkerThread(); - MOZ_ASSERT(mWorkerHolder); - mWorkerHolder = nullptr; -} - /* * Checks: * 1) Is aWorker allowed to show a notification for scope? diff --git a/dom/notification/Notification.h b/dom/notification/Notification.h index 80fdd1667804..019ce6be3e59 100644 --- a/dom/notification/Notification.h +++ b/dom/notification/Notification.h @@ -10,7 +10,6 @@ #include "mozilla/DOMEventTargetHelper.h" #include "mozilla/UniquePtr.h" #include "mozilla/dom/NotificationBinding.h" -#include "mozilla/dom/WorkerHolder.h" #include "nsIObserver.h" #include "nsISupports.h" @@ -32,20 +31,9 @@ namespace dom { class NotificationRef; class WorkerNotificationObserver; class Promise; +class StrongWorkerRef; class WorkerPrivate; -class Notification; -class NotificationWorkerHolder final : public WorkerHolder { - // Since the feature is strongly held by a Notification, it is ok to hold - // a raw pointer here. - Notification* mNotification; - - public: - explicit NotificationWorkerHolder(Notification* aNotification); - - bool Notify(WorkerStatus aStatus) override; -}; - // Records telemetry probes at application startup, when a notification is // shown, and when the notification permission is revoked for a site. class NotificationTelemetryService final : public nsIObserver { @@ -385,13 +373,12 @@ class Notification : public DOMEventTargetHelper, bool IsTargetThread() const { return NS_IsMainThread() == !mWorkerPrivate; } - bool RegisterWorkerHolder(); - void UnregisterWorkerHolder(); + bool CreateWorkerRef(); nsresult ResolveIconAndSoundURL(nsString&, nsString&); // Only used for Notifications on Workers, worker thread only. - UniquePtr mWorkerHolder; + RefPtr mWorkerRef; // Target thread only. uint32_t mTaskCount; }; diff --git a/dom/performance/PerformanceStorageWorker.cpp b/dom/performance/PerformanceStorageWorker.cpp index 0342dcfdeb07..19d5b7a3171a 100644 --- a/dom/performance/PerformanceStorageWorker.cpp +++ b/dom/performance/PerformanceStorageWorker.cpp @@ -59,26 +59,6 @@ class PerformanceEntryAdder final : public WorkerControlRunnable { UniquePtr mData; }; -class PerformanceStorageWorkerHolder final : public WorkerHolder { - RefPtr mStorage; - - public: - explicit PerformanceStorageWorkerHolder(PerformanceStorageWorker* aStorage) - : WorkerHolder("PerformanceStorageWorkerHolder", - WorkerHolder::AllowIdleShutdownStart), - mStorage(aStorage) {} - - bool Notify(WorkerStatus aStatus) override { - if (mStorage) { - RefPtr storage; - storage.swap(mStorage); - storage->ShutdownOnWorker(); - } - - return true; - } -}; - } // namespace /* static */ diff --git a/dom/serviceworkers/RemoteServiceWorkerContainerImpl.cpp b/dom/serviceworkers/RemoteServiceWorkerContainerImpl.cpp index ee0c1bf8bf7f..48d5bb54f8f2 100644 --- a/dom/serviceworkers/RemoteServiceWorkerContainerImpl.cpp +++ b/dom/serviceworkers/RemoteServiceWorkerContainerImpl.cpp @@ -199,22 +199,12 @@ RemoteServiceWorkerContainerImpl::RemoteServiceWorkerContainerImpl() return; } - RefPtr workerHolderToken; - if (!NS_IsMainThread()) { - WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate(); - MOZ_DIAGNOSTIC_ASSERT(workerPrivate); - - workerHolderToken = WorkerHolderToken::Create( - workerPrivate, Canceling, WorkerHolderToken::AllowIdleShutdownStart); - - if (NS_WARN_IF(!workerHolderToken)) { - Shutdown(); - return; - } + ServiceWorkerContainerChild* actor = ServiceWorkerContainerChild::Create(); + if (NS_WARN_IF(!actor)) { + Shutdown(); + return; } - ServiceWorkerContainerChild* actor = - new ServiceWorkerContainerChild(workerHolderToken); PServiceWorkerContainerChild* sentActor = parentActor->SendPServiceWorkerContainerConstructor(actor); if (NS_WARN_IF(!sentActor)) { diff --git a/dom/serviceworkers/RemoteServiceWorkerImpl.cpp b/dom/serviceworkers/RemoteServiceWorkerImpl.cpp index dc98229ca993..7625cc396160 100644 --- a/dom/serviceworkers/RemoteServiceWorkerImpl.cpp +++ b/dom/serviceworkers/RemoteServiceWorkerImpl.cpp @@ -85,21 +85,12 @@ RemoteServiceWorkerImpl::RemoteServiceWorkerImpl( return; } - RefPtr workerHolderToken; - if (!NS_IsMainThread()) { - WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate(); - MOZ_DIAGNOSTIC_ASSERT(workerPrivate); - - workerHolderToken = WorkerHolderToken::Create( - workerPrivate, Canceling, WorkerHolderToken::AllowIdleShutdownStart); - - if (NS_WARN_IF(!workerHolderToken)) { - Shutdown(); - return; - } + ServiceWorkerChild* actor = ServiceWorkerChild::Create(); + if (NS_WARN_IF(!actor)) { + Shutdown(); + return; } - ServiceWorkerChild* actor = new ServiceWorkerChild(workerHolderToken); PServiceWorkerChild* sentActor = parentActor->SendPServiceWorkerConstructor(actor, aDescriptor.ToIPC()); if (NS_WARN_IF(!sentActor)) { diff --git a/dom/serviceworkers/RemoteServiceWorkerRegistrationImpl.cpp b/dom/serviceworkers/RemoteServiceWorkerRegistrationImpl.cpp index a4230c9b255c..8ade4cdea561 100644 --- a/dom/serviceworkers/RemoteServiceWorkerRegistrationImpl.cpp +++ b/dom/serviceworkers/RemoteServiceWorkerRegistrationImpl.cpp @@ -114,22 +114,13 @@ RemoteServiceWorkerRegistrationImpl::RemoteServiceWorkerRegistrationImpl( return; } - RefPtr workerHolderToken; - if (!NS_IsMainThread()) { - WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate(); - MOZ_DIAGNOSTIC_ASSERT(workerPrivate); - - workerHolderToken = WorkerHolderToken::Create( - workerPrivate, Canceling, WorkerHolderToken::AllowIdleShutdownStart); - - if (NS_WARN_IF(!workerHolderToken)) { - Shutdown(); - return; - } + ServiceWorkerRegistrationChild* actor = + ServiceWorkerRegistrationChild::Create(); + if (NS_WARN_IF(!actor)) { + Shutdown(); + return; } - ServiceWorkerRegistrationChild* actor = - new ServiceWorkerRegistrationChild(workerHolderToken); PServiceWorkerRegistrationChild* sentActor = parentActor->SendPServiceWorkerRegistrationConstructor( actor, aDescriptor.ToIPC()); diff --git a/dom/serviceworkers/ServiceWorkerChild.cpp b/dom/serviceworkers/ServiceWorkerChild.cpp index ab52031ae58c..063a137d7e19 100644 --- a/dom/serviceworkers/ServiceWorkerChild.cpp +++ b/dom/serviceworkers/ServiceWorkerChild.cpp @@ -5,15 +5,13 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "ServiceWorkerChild.h" +#include "mozilla/dom/WorkerRef.h" namespace mozilla { namespace dom { void ServiceWorkerChild::ActorDestroy(ActorDestroyReason aReason) { - if (mWorkerHolderToken) { - mWorkerHolderToken->RemoveListener(this); - mWorkerHolderToken = nullptr; - } + mIPCWorkerRef = nullptr; if (mOwner) { mOwner->RevokeActor(this); @@ -21,17 +19,33 @@ void ServiceWorkerChild::ActorDestroy(ActorDestroyReason aReason) { } } -void ServiceWorkerChild::WorkerShuttingDown() { MaybeStartTeardown(); } +// static +ServiceWorkerChild* ServiceWorkerChild::Create() { + ServiceWorkerChild* actor = new ServiceWorkerChild(); -ServiceWorkerChild::ServiceWorkerChild(WorkerHolderToken* aWorkerHolderToken) - : mWorkerHolderToken(aWorkerHolderToken), - mOwner(nullptr), - mTeardownStarted(false) { - if (mWorkerHolderToken) { - mWorkerHolderToken->AddListener(this); + if (!NS_IsMainThread()) { + WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate(); + MOZ_DIAGNOSTIC_ASSERT(workerPrivate); + + RefPtr> helper = + new IPCWorkerRefHelper(actor); + + actor->mIPCWorkerRef = IPCWorkerRef::Create( + workerPrivate, "ServiceWorkerChild", + [helper] { helper->Actor()->MaybeStartTeardown(); }); + + if (NS_WARN_IF(!actor->mIPCWorkerRef)) { + delete actor; + return nullptr; + } } + + return actor; } +ServiceWorkerChild::ServiceWorkerChild() + : mOwner(nullptr), mTeardownStarted(false) {} + void ServiceWorkerChild::SetOwner(RemoteServiceWorkerImpl* aOwner) { MOZ_DIAGNOSTIC_ASSERT(!mOwner); MOZ_DIAGNOSTIC_ASSERT(aOwner); diff --git a/dom/serviceworkers/ServiceWorkerChild.h b/dom/serviceworkers/ServiceWorkerChild.h index 84ba7ebd3857..287fcafc08da 100644 --- a/dom/serviceworkers/ServiceWorkerChild.h +++ b/dom/serviceworkers/ServiceWorkerChild.h @@ -8,27 +8,26 @@ #define mozilla_dom_serviceworkerchild_h__ #include "mozilla/dom/PServiceWorkerChild.h" -#include "mozilla/dom/WorkerHolderToken.h" namespace mozilla { namespace dom { +class IPCWorkerRef; class RemoteServiceWorkerImpl; -class ServiceWorkerChild final : public PServiceWorkerChild, - public WorkerHolderToken::Listener { - RefPtr mWorkerHolderToken; +class ServiceWorkerChild final : public PServiceWorkerChild { + RefPtr mIPCWorkerRef; RemoteServiceWorkerImpl* mOwner; bool mTeardownStarted; + ServiceWorkerChild(); + // PServiceWorkerChild void ActorDestroy(ActorDestroyReason aReason) override; - // WorkerHolderToken::Listener - void WorkerShuttingDown() override; - public: - explicit ServiceWorkerChild(WorkerHolderToken* aWorkerHolderToken); + static ServiceWorkerChild* Create(); + ~ServiceWorkerChild() = default; void SetOwner(RemoteServiceWorkerImpl* aOwner); diff --git a/dom/serviceworkers/ServiceWorkerContainerChild.cpp b/dom/serviceworkers/ServiceWorkerContainerChild.cpp index 2699defad4ce..c554da28a511 100644 --- a/dom/serviceworkers/ServiceWorkerContainerChild.cpp +++ b/dom/serviceworkers/ServiceWorkerContainerChild.cpp @@ -5,6 +5,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "mozilla/dom/PServiceWorkerContainerChild.h" +#include "mozilla/dom/WorkerRef.h" #include "RemoteServiceWorkerContainerImpl.h" @@ -12,10 +13,7 @@ namespace mozilla { namespace dom { void ServiceWorkerContainerChild::ActorDestroy(ActorDestroyReason aReason) { - if (mWorkerHolderToken) { - mWorkerHolderToken->RemoveListener(this); - mWorkerHolderToken = nullptr; - } + mIPCWorkerRef = nullptr; if (mOwner) { mOwner->RevokeActor(this); @@ -23,18 +21,32 @@ void ServiceWorkerContainerChild::ActorDestroy(ActorDestroyReason aReason) { } } -void ServiceWorkerContainerChild::WorkerShuttingDown() { MaybeStartTeardown(); } +// static +ServiceWorkerContainerChild* ServiceWorkerContainerChild::Create() { + ServiceWorkerContainerChild* actor = new ServiceWorkerContainerChild(); -ServiceWorkerContainerChild::ServiceWorkerContainerChild( - WorkerHolderToken* aWorkerHolderToken) - : mWorkerHolderToken(aWorkerHolderToken), - mOwner(nullptr), - mTeardownStarted(false) { - if (mWorkerHolderToken) { - mWorkerHolderToken->AddListener(this); + if (!NS_IsMainThread()) { + WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate(); + MOZ_DIAGNOSTIC_ASSERT(workerPrivate); + + RefPtr> helper = + new IPCWorkerRefHelper(actor); + + actor->mIPCWorkerRef = IPCWorkerRef::Create( + workerPrivate, "ServiceWorkerContainerChild", + [helper] { helper->Actor()->MaybeStartTeardown(); }); + if (NS_WARN_IF(!actor->mIPCWorkerRef)) { + delete actor; + return nullptr; + } } + + return actor; } +ServiceWorkerContainerChild::ServiceWorkerContainerChild() + : mOwner(nullptr), mTeardownStarted(false) {} + void ServiceWorkerContainerChild::SetOwner( RemoteServiceWorkerContainerImpl* aOwner) { MOZ_DIAGNOSTIC_ASSERT(!mOwner); diff --git a/dom/serviceworkers/ServiceWorkerContainerChild.h b/dom/serviceworkers/ServiceWorkerContainerChild.h index 70fe3ea4de7e..7788ec1caa56 100644 --- a/dom/serviceworkers/ServiceWorkerContainerChild.h +++ b/dom/serviceworkers/ServiceWorkerContainerChild.h @@ -8,25 +8,25 @@ #define mozilla_dom_serviceworkercontainerchild_h__ #include "mozilla/dom/PServiceWorkerContainerChild.h" -#include "mozilla/dom/WorkerHolderToken.h" namespace mozilla { namespace dom { -class ServiceWorkerContainerChild final : public PServiceWorkerContainerChild, - public WorkerHolderToken::Listener { - RefPtr mWorkerHolderToken; +class IPCWorkerRef; + +class ServiceWorkerContainerChild final : public PServiceWorkerContainerChild { + RefPtr mIPCWorkerRef; RemoteServiceWorkerContainerImpl* mOwner; bool mTeardownStarted; + ServiceWorkerContainerChild(); + // PServiceWorkerContainerChild void ActorDestroy(ActorDestroyReason aReason) override; - // WorkerHolderToken::Listener - void WorkerShuttingDown() override; - public: - explicit ServiceWorkerContainerChild(WorkerHolderToken* aWorkerHolderToken); + static ServiceWorkerContainerChild* Create(); + ~ServiceWorkerContainerChild() = default; void SetOwner(RemoteServiceWorkerContainerImpl* aOwner); diff --git a/dom/serviceworkers/ServiceWorkerRegistrationChild.cpp b/dom/serviceworkers/ServiceWorkerRegistrationChild.cpp index c5eb4f5814c9..0ef4444905cf 100644 --- a/dom/serviceworkers/ServiceWorkerRegistrationChild.cpp +++ b/dom/serviceworkers/ServiceWorkerRegistrationChild.cpp @@ -14,10 +14,7 @@ namespace dom { using mozilla::ipc::IPCResult; void ServiceWorkerRegistrationChild::ActorDestroy(ActorDestroyReason aReason) { - if (mWorkerHolderToken) { - mWorkerHolderToken->RemoveListener(this); - mWorkerHolderToken = nullptr; - } + mIPCWorkerRef = nullptr; if (mOwner) { mOwner->RevokeActor(this); @@ -40,19 +37,32 @@ IPCResult ServiceWorkerRegistrationChild::RecvFireUpdateFound() { return IPC_OK(); } -void ServiceWorkerRegistrationChild::WorkerShuttingDown() { - MaybeStartTeardown(); +// static +ServiceWorkerRegistrationChild* ServiceWorkerRegistrationChild::Create() { + ServiceWorkerRegistrationChild* actor = new ServiceWorkerRegistrationChild(); + + if (!NS_IsMainThread()) { + WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate(); + MOZ_DIAGNOSTIC_ASSERT(workerPrivate); + + RefPtr> helper = + new IPCWorkerRefHelper(actor); + + actor->mIPCWorkerRef = IPCWorkerRef::Create( + workerPrivate, "ServiceWorkerRegistrationChild", + [helper] { helper->Actor()->MaybeStartTeardown(); }); + + if (NS_WARN_IF(!actor->mIPCWorkerRef)) { + delete actor; + return nullptr; + } + } + + return actor; } -ServiceWorkerRegistrationChild::ServiceWorkerRegistrationChild( - WorkerHolderToken* aWorkerHolderToken) - : mWorkerHolderToken(aWorkerHolderToken), - mOwner(nullptr), - mTeardownStarted(false) { - if (mWorkerHolderToken) { - mWorkerHolderToken->AddListener(this); - } -} +ServiceWorkerRegistrationChild::ServiceWorkerRegistrationChild() + : mOwner(nullptr), mTeardownStarted(false) {} void ServiceWorkerRegistrationChild::SetOwner( RemoteServiceWorkerRegistrationImpl* aOwner) { diff --git a/dom/serviceworkers/ServiceWorkerRegistrationChild.h b/dom/serviceworkers/ServiceWorkerRegistrationChild.h index 5060e9b78605..a301287d13d7 100644 --- a/dom/serviceworkers/ServiceWorkerRegistrationChild.h +++ b/dom/serviceworkers/ServiceWorkerRegistrationChild.h @@ -8,20 +8,21 @@ #define mozilla_dom_serviceworkerregistrationchild_h__ #include "mozilla/dom/PServiceWorkerRegistrationChild.h" -#include "mozilla/dom/WorkerHolderToken.h" namespace mozilla { namespace dom { +class IPCWorkerRef; class RemoteServiceWorkerRegistrationImpl; class ServiceWorkerRegistrationChild final - : public PServiceWorkerRegistrationChild, - public WorkerHolderToken::Listener { - RefPtr mWorkerHolderToken; + : public PServiceWorkerRegistrationChild { + RefPtr mIPCWorkerRef; RemoteServiceWorkerRegistrationImpl* mOwner; bool mTeardownStarted; + ServiceWorkerRegistrationChild(); + // PServiceWorkerRegistrationChild void ActorDestroy(ActorDestroyReason aReason) override; @@ -30,12 +31,9 @@ class ServiceWorkerRegistrationChild final mozilla::ipc::IPCResult RecvFireUpdateFound() override; - // WorkerHolderToken::Listener - void WorkerShuttingDown() override; - public: - explicit ServiceWorkerRegistrationChild( - WorkerHolderToken* aWorkerHolderToken); + static ServiceWorkerRegistrationChild* Create(); + ~ServiceWorkerRegistrationChild() = default; void SetOwner(RemoteServiceWorkerRegistrationImpl* aOwner); diff --git a/dom/webidl/AudioContext.webidl b/dom/webidl/AudioContext.webidl index 66fccffb8c57..08e7984f2ecc 100644 --- a/dom/webidl/AudioContext.webidl +++ b/dom/webidl/AudioContext.webidl @@ -14,12 +14,18 @@ dictionary AudioContextOptions { float sampleRate = 0; }; +dictionary AudioTimestamp { + double contextTime; + DOMHighResTimeStamp performanceTime; +}; + [Pref="dom.webaudio.enabled", Constructor(optional AudioContextOptions contextOptions = {})] interface AudioContext : BaseAudioContext { - // Bug 1324545: readonly attribute double outputLatency; - // Bug 1324545: AudioTimestamp getOutputTimestamp (); + readonly attribute double baseLatency; + readonly attribute double outputLatency; + AudioTimestamp getOutputTimestamp(); [Throws] Promise suspend(); diff --git a/dom/webidl/BaseAudioContext.webidl b/dom/webidl/BaseAudioContext.webidl index 6d7027d651af..c3848131093c 100644 --- a/dom/webidl/BaseAudioContext.webidl +++ b/dom/webidl/BaseAudioContext.webidl @@ -27,7 +27,6 @@ interface BaseAudioContext : EventTarget { readonly attribute AudioContextState state; [Throws, SameObject, SecureContext, Pref="dom.audioworklet.enabled"] readonly attribute AudioWorklet audioWorklet; - // Bug 1324552: readonly attribute double baseLatency; [Throws] Promise resume(); diff --git a/dom/webidl/MediaElementAudioSourceNode.webidl b/dom/webidl/MediaElementAudioSourceNode.webidl index 37de32536d24..d8009a836350 100644 --- a/dom/webidl/MediaElementAudioSourceNode.webidl +++ b/dom/webidl/MediaElementAudioSourceNode.webidl @@ -17,7 +17,7 @@ dictionary MediaElementAudioSourceOptions { [Pref="dom.webaudio.enabled", Constructor(AudioContext context, MediaElementAudioSourceOptions options)] interface MediaElementAudioSourceNode : AudioNode { - + readonly attribute HTMLMediaElement mediaElement; }; // Mozilla extensions diff --git a/dom/webidl/MediaStreamAudioSourceNode.webidl b/dom/webidl/MediaStreamAudioSourceNode.webidl index 06727a5dadd2..e08620ce70d1 100644 --- a/dom/webidl/MediaStreamAudioSourceNode.webidl +++ b/dom/webidl/MediaStreamAudioSourceNode.webidl @@ -17,7 +17,8 @@ dictionary MediaStreamAudioSourceOptions { [Pref="dom.webaudio.enabled", Constructor(AudioContext context, MediaStreamAudioSourceOptions options)] interface MediaStreamAudioSourceNode : AudioNode { - + [BinaryName="GetMediaStream"] + readonly attribute MediaStream mediaStream; }; // Mozilla extensions diff --git a/dom/workers/ScriptLoader.cpp b/dom/workers/ScriptLoader.cpp index 4b1b2621dfb3..df55c6f99b94 100644 --- a/dom/workers/ScriptLoader.cpp +++ b/dom/workers/ScriptLoader.cpp @@ -73,7 +73,6 @@ #include "mozilla/dom/ServiceWorkerManager.h" #include "mozilla/UniquePtr.h" #include "Principal.h" -#include "WorkerHolder.h" #include "WorkerPrivate.h" #include "WorkerRunnable.h" #include "WorkerScope.h" diff --git a/dom/workers/WorkerHolder.cpp b/dom/workers/WorkerHolder.cpp deleted file mode 100644 index 197ad6f6d119..000000000000 --- a/dom/workers/WorkerHolder.cpp +++ /dev/null @@ -1,71 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "WorkerHolder.h" -#include "WorkerPrivate.h" - -namespace mozilla { -namespace dom { - -namespace { - -void AssertOnOwningThread(void* aThread) { - if (MOZ_UNLIKELY(aThread != GetCurrentVirtualThread())) { - MOZ_CRASH_UNSAFE("WorkerHolder on the wrong thread."); - } -} - -} // namespace - -WorkerHolder::WorkerHolder(const char* aName, Behavior aBehavior) - : mWorkerPrivate(nullptr), - mBehavior(aBehavior), - mThread(GetCurrentVirtualThread()), - mName(aName) {} - -WorkerHolder::~WorkerHolder() { - AssertOnOwningThread(mThread); - ReleaseWorkerInternal(); - MOZ_ASSERT(mWorkerPrivate == nullptr); -} - -bool WorkerHolder::HoldWorker(WorkerPrivate* aWorkerPrivate, - WorkerStatus aFailStatus) { - AssertOnOwningThread(mThread); - MOZ_ASSERT(aWorkerPrivate); - MOZ_ASSERT(aFailStatus >= Canceling); - - aWorkerPrivate->AssertIsOnWorkerThread(); - - if (!aWorkerPrivate->AddHolder(this, aFailStatus)) { - return false; - } - - mWorkerPrivate = aWorkerPrivate; - return true; -} - -void WorkerHolder::ReleaseWorker() { - AssertOnOwningThread(mThread); - MOZ_ASSERT(mWorkerPrivate); - - ReleaseWorkerInternal(); -} - -WorkerHolder::Behavior WorkerHolder::GetBehavior() const { return mBehavior; } - -void WorkerHolder::ReleaseWorkerInternal() { - AssertOnOwningThread(mThread); - - if (mWorkerPrivate) { - mWorkerPrivate->AssertIsOnWorkerThread(); - mWorkerPrivate->RemoveHolder(this); - mWorkerPrivate = nullptr; - } -} - -} // namespace dom -} // namespace mozilla diff --git a/dom/workers/WorkerHolderToken.cpp b/dom/workers/WorkerHolderToken.cpp deleted file mode 100644 index 03dd73a40a1e..000000000000 --- a/dom/workers/WorkerHolderToken.cpp +++ /dev/null @@ -1,99 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "WorkerHolderToken.h" - -#include "WorkerPrivate.h" - -namespace mozilla { -namespace dom { - -// static -already_AddRefed WorkerHolderToken::Create( - WorkerPrivate* aWorkerPrivate, WorkerStatus aShutdownStatus, - Behavior aBehavior) { - MOZ_DIAGNOSTIC_ASSERT(aWorkerPrivate); - aWorkerPrivate->AssertIsOnWorkerThread(); - - RefPtr workerHolder = - new WorkerHolderToken(aShutdownStatus, aBehavior); - - if (NS_WARN_IF(!workerHolder->HoldWorker(aWorkerPrivate, aShutdownStatus))) { - return nullptr; - } - - return workerHolder.forget(); -} - -void WorkerHolderToken::AddListener(Listener* aListener) { - NS_ASSERT_OWNINGTHREAD(WorkerHolderToken); - MOZ_ASSERT(aListener); - MOZ_ASSERT(!mListenerList.Contains(aListener)); - - mListenerList.AppendElement(aListener); - - // Allow an actor to be added after we've entered the Notifying case. We - // can't stop the actor creation from racing with out destruction of the - // other actors and we need to wait for this extra one to close as well. - // Signal it should destroy itself right away. - if (mShuttingDown) { - aListener->WorkerShuttingDown(); - } -} - -void WorkerHolderToken::RemoveListener(Listener* aListener) { - NS_ASSERT_OWNINGTHREAD(WorkerHolderToken); - MOZ_ASSERT(aListener); - - DebugOnly removed = mListenerList.RemoveElement(aListener); - - MOZ_ASSERT(removed); - MOZ_ASSERT(!mListenerList.Contains(aListener)); -} - -bool WorkerHolderToken::IsShuttingDown() const { return mShuttingDown; } - -WorkerPrivate* WorkerHolderToken::GetWorkerPrivate() const { - NS_ASSERT_OWNINGTHREAD(WorkerHolderToken); - return mWorkerPrivate; -} - -WorkerHolderToken::WorkerHolderToken(WorkerStatus aShutdownStatus, - Behavior aBehavior) - : WorkerHolder("WorkerHolderToken", aBehavior), - mShutdownStatus(aShutdownStatus), - mShuttingDown(false) {} - -WorkerHolderToken::~WorkerHolderToken() { - NS_ASSERT_OWNINGTHREAD(WorkerHolderToken); - MOZ_ASSERT(mListenerList.IsEmpty()); -} - -bool WorkerHolderToken::Notify(WorkerStatus aStatus) { - NS_ASSERT_OWNINGTHREAD(WorkerHolderToken); - - // When the service worker thread is stopped we will get Canceling, - // but nothing higher than that. We must shut things down at Canceling. - if (aStatus < mShutdownStatus || mShuttingDown) { - return true; - } - - // Start the asynchronous destruction of our actors. These will call back - // into RemoveActor() once the actor is destroyed. - nsTObserverArray::ForwardIterator iter(mListenerList); - while (iter.HasMore()) { - iter.GetNext()->WorkerShuttingDown(); - } - - // Set this after calling WorkerShuttingDown() on listener list in case - // one callback triggers another listener to be added. - mShuttingDown = true; - - return true; -} - -} // namespace dom -} // namespace mozilla diff --git a/dom/workers/WorkerHolderToken.h b/dom/workers/WorkerHolderToken.h deleted file mode 100644 index 3f63a3ae4719..000000000000 --- a/dom/workers/WorkerHolderToken.h +++ /dev/null @@ -1,74 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_dom_workers_WorkerHolderToken_h -#define mozilla_dom_workers_WorkerHolderToken_h - -#include "nsISupportsImpl.h" -#include "nsTObserverArray.h" -#include "WorkerHolder.h" - -namespace mozilla { -namespace dom { - -class WorkerPrivate; - -// This is a ref-counted WorkerHolder implementation. If you wish -// to be notified of worker shutdown beginning, then you can implement -// the Listener interface and call AddListener(). -// -// This is purely a convenience class to avoid requiring code to -// extend WorkerHolder all the time. -class WorkerHolderToken final : public WorkerHolder { - public: - // Pure virtual class defining the interface for objects that - // wish to be notified of worker shutdown. - class Listener { - public: - virtual void WorkerShuttingDown() = 0; - }; - - // Attempt to create a WorkerHolderToken(). If the shutdown has already - // passed the given shutdown phase or fails for another reason then - // nullptr is returned. - static already_AddRefed Create( - WorkerPrivate* aWorkerPrivate, WorkerStatus aShutdownStatus, - Behavior aBehavior = PreventIdleShutdownStart); - - // Add a listener to the token. Note, this does not hold a strong - // reference to the listener. You must call RemoveListener() before - // the listener is destroyed. This can only be called on the owning - // worker thread. - void AddListener(Listener* aListener); - - // Remove a previously added listener. This can only be called on the - // owning worker thread. - void RemoveListener(Listener* aListener); - - bool IsShuttingDown() const; - - WorkerPrivate* GetWorkerPrivate() const; - - private: - WorkerHolderToken(WorkerStatus aShutdownStatus, Behavior aBehavior); - - ~WorkerHolderToken(); - - // WorkerHolder methods - virtual bool Notify(WorkerStatus aStatus) override; - - nsTObserverArray mListenerList; - const WorkerStatus mShutdownStatus; - bool mShuttingDown; - - public: - NS_INLINE_DECL_REFCOUNTING(WorkerHolderToken) -}; - -} // namespace dom -} // namespace mozilla - -#endif // mozilla_dom_workers_WorkerHolderToken_h diff --git a/dom/workers/WorkerPrivate.cpp b/dom/workers/WorkerPrivate.cpp index f34ee7cf5baa..80090c0624df 100644 --- a/dom/workers/WorkerPrivate.cpp +++ b/dom/workers/WorkerPrivate.cpp @@ -2047,7 +2047,7 @@ bool WorkerPrivate::PrincipalIsValid() const { WorkerPrivate::WorkerThreadAccessible::WorkerThreadAccessible( WorkerPrivate* const aParent) - : mNumHoldersPreventingShutdownStart(0), + : mNumWorkerRefsPreventingShutdownStart(0), mDebuggerEventLoopLevel(0), mErrorHandlerRecursionCount(0), mNextTimeoutId(1), @@ -2706,7 +2706,7 @@ void WorkerPrivate::DoRunLoop(JSContext* aCx) { while (mControlQueue.IsEmpty() && !(debuggerRunnablesPending = !mDebuggerQueue.IsEmpty()) && !(normalRunnablesPending = NS_HasPendingEvents(mThread)) && - !(mStatus != Running && !HasActiveHolders())) { + !(mStatus != Running && !HasActiveWorkerRefs())) { WaitForWorkerEvents(); } @@ -2724,7 +2724,7 @@ void WorkerPrivate::DoRunLoop(JSContext* aCx) { } // if all holders are done then we can kill this thread. - if (currentStatus != Running && !HasActiveHolders()) { + if (currentStatus != Running && !HasActiveWorkerRefs()) { // Now we are ready to kill the worker thread. if (currentStatus == Canceling) { NotifyInternal(Killing); @@ -3503,7 +3503,9 @@ void WorkerPrivate::RemoveChildWorker(WorkerPrivate* aChildWorker) { } } -bool WorkerPrivate::AddHolder(WorkerHolder* aHolder, WorkerStatus aFailStatus) { +bool WorkerPrivate::AddWorkerRef(WorkerRef* aWorkerRef, + WorkerStatus aFailStatus) { + MOZ_ASSERT(aWorkerRef); MOZ_ACCESS_THREAD_BOUND(mWorkerThreadAccessible, data); { @@ -3514,46 +3516,46 @@ bool WorkerPrivate::AddHolder(WorkerHolder* aHolder, WorkerStatus aFailStatus) { } } - MOZ_ASSERT(!data->mHolders.Contains(aHolder), "Already know about this one!"); + MOZ_ASSERT(!data->mWorkerRefs.Contains(aWorkerRef), + "Already know about this one!"); - if (aHolder->GetBehavior() == WorkerHolder::PreventIdleShutdownStart) { - if (!data->mNumHoldersPreventingShutdownStart && + if (aWorkerRef->IsPreventingShutdown()) { + if (!data->mNumWorkerRefsPreventingShutdownStart && !ModifyBusyCountFromWorker(true)) { return false; } - data->mNumHoldersPreventingShutdownStart += 1; + data->mNumWorkerRefsPreventingShutdownStart += 1; } - data->mHolders.AppendElement(aHolder); + data->mWorkerRefs.AppendElement(aWorkerRef); return true; } -void WorkerPrivate::RemoveHolder(WorkerHolder* aHolder) { +void WorkerPrivate::RemoveWorkerRef(WorkerRef* aWorkerRef) { + MOZ_ASSERT(aWorkerRef); MOZ_ACCESS_THREAD_BOUND(mWorkerThreadAccessible, data); - MOZ_ASSERT(data->mHolders.Contains(aHolder), "Didn't know about this one!"); - data->mHolders.RemoveElement(aHolder); + MOZ_ASSERT(data->mWorkerRefs.Contains(aWorkerRef), + "Didn't know about this one!"); + data->mWorkerRefs.RemoveElement(aWorkerRef); - if (aHolder->GetBehavior() == WorkerHolder::PreventIdleShutdownStart) { - data->mNumHoldersPreventingShutdownStart -= 1; - if (!data->mNumHoldersPreventingShutdownStart && + if (aWorkerRef->IsPreventingShutdown()) { + data->mNumWorkerRefsPreventingShutdownStart -= 1; + if (!data->mNumWorkerRefsPreventingShutdownStart && !ModifyBusyCountFromWorker(false)) { NS_WARNING("Failed to modify busy count!"); } } } -void WorkerPrivate::NotifyHolders(WorkerStatus aStatus) { +void WorkerPrivate::NotifyWorkerRefs(WorkerStatus aStatus) { MOZ_ACCESS_THREAD_BOUND(mWorkerThreadAccessible, data); NS_ASSERTION(aStatus > Closing, "Bad status!"); - nsTObserverArray::ForwardIterator iter(data->mHolders); + nsTObserverArray::ForwardIterator iter(data->mWorkerRefs); while (iter.HasMore()) { - WorkerHolder* holder = iter.GetNext(); - if (!holder->Notify(aStatus)) { - NS_WARNING("Failed to notify holder!"); - } + iter.GetNext()->Notify(); } AutoTArray children; @@ -4060,7 +4062,7 @@ bool WorkerPrivate::NotifyInternal(WorkerStatus aStatus) { // Let all our holders know the new status. if (aStatus > Closing) { - NotifyHolders(aStatus); + NotifyWorkerRefs(aStatus); } // If this is the first time our status has changed then we need to clear the @@ -4801,11 +4803,13 @@ void WorkerPrivate::AssertIsOnWorkerThread() const { void WorkerPrivate::DumpCrashInformation(nsACString& aString) { MOZ_ACCESS_THREAD_BOUND(mWorkerThreadAccessible, data); - nsTObserverArray::ForwardIterator iter(data->mHolders); + nsTObserverArray::ForwardIterator iter(data->mWorkerRefs); while (iter.HasMore()) { - WorkerHolder* holder = iter.GetNext(); - aString.Append("|"); - aString.Append(holder->Name()); + WorkerRef* workerRef = iter.GetNext(); + if (workerRef->IsPreventingShutdown()) { + aString.Append("|"); + aString.Append(workerRef->Name()); + } } } diff --git a/dom/workers/WorkerPrivate.h b/dom/workers/WorkerPrivate.h index 4f403f71e4ab..cc930bdecb0d 100644 --- a/dom/workers/WorkerPrivate.h +++ b/dom/workers/WorkerPrivate.h @@ -8,6 +8,7 @@ #define mozilla_dom_workers_workerprivate_h__ #include "mozilla/dom/WorkerCommon.h" +#include "mozilla/dom/WorkerStatus.h" #include "mozilla/Attributes.h" #include "mozilla/CondVar.h" #include "mozilla/DOMEventTargetHelper.h" @@ -20,7 +21,6 @@ #include "js/ContextOptions.h" #include "mozilla/dom/Worker.h" -#include "mozilla/dom/WorkerHolder.h" #include "mozilla/dom/WorkerLoadInfo.h" #include "mozilla/dom/workerinternals/JSSettings.h" #include "mozilla/dom/workerinternals/Queue.h" @@ -52,6 +52,7 @@ class WorkerDebuggerGlobalScope; class WorkerErrorReport; class WorkerEventTarget; class WorkerGlobalScope; +class WorkerRef; class WorkerRunnable; class WorkerDebuggeeRunnable; class WorkerThread; @@ -922,7 +923,7 @@ class WorkerPrivate : public RelativeTimeline { void WaitForWorkerEvents(); // If the worker shutdown status is equal or greater then aFailStatus, this - // operation will fail and nullptr will be returned. See WorkerHolder.h for + // operation will fail and nullptr will be returned. See WorkerStatus.h for // more information about the correct value to use. already_AddRefed CreateNewSyncLoop(WorkerStatus aFailStatus); @@ -938,16 +939,18 @@ class WorkerPrivate : public RelativeTimeline { void ShutdownGCTimers(); - bool AddHolder(WorkerHolder* aHolder, WorkerStatus aFailStatus); + friend class WorkerRef; - void RemoveHolder(WorkerHolder* aHolder); + bool AddWorkerRef(WorkerRef* aWorkerRefer, WorkerStatus aFailStatus); - void NotifyHolders(WorkerStatus aStatus); + void RemoveWorkerRef(WorkerRef* aWorkerRef); - bool HasActiveHolders() { + void NotifyWorkerRefs(WorkerStatus aStatus); + + bool HasActiveWorkerRefs() { MOZ_ACCESS_THREAD_BOUND(mWorkerThreadAccessible, data); return !(data->mChildWorkers.IsEmpty() && data->mTimeouts.IsEmpty() && - data->mHolders.IsEmpty()); + data->mWorkerRefs.IsEmpty()); } // Internal logic to dispatch a runnable. This is separate from Dispatch() @@ -965,7 +968,6 @@ class WorkerPrivate : public RelativeTimeline { class EventTarget; friend class EventTarget; - friend class mozilla::dom::WorkerHolder; friend class AutoSyncLoopHolder; struct TimeoutInfo; @@ -1084,7 +1086,7 @@ class WorkerPrivate : public RelativeTimeline { RefPtr mScope; RefPtr mDebuggerScope; nsTArray mChildWorkers; - nsTObserverArray mHolders; + nsTObserverArray mWorkerRefs; nsTArray> mTimeouts; nsCOMPtr mTimer; @@ -1096,7 +1098,7 @@ class WorkerPrivate : public RelativeTimeline { UniquePtr mClientSource; - uint32_t mNumHoldersPreventingShutdownStart; + uint32_t mNumWorkerRefsPreventingShutdownStart; uint32_t mDebuggerEventLoopLevel; uint32_t mErrorHandlerRecursionCount; diff --git a/dom/workers/WorkerRef.cpp b/dom/workers/WorkerRef.cpp index 255b0ec65e65..f057d65a117c 100644 --- a/dom/workers/WorkerRef.cpp +++ b/dom/workers/WorkerRef.cpp @@ -7,7 +7,6 @@ #include "WorkerRef.h" #include "mozilla/Unused.h" -#include "WorkerHolder.h" #include "WorkerRunnable.h" #include "WorkerPrivate.h" @@ -43,46 +42,50 @@ class ReleaseRefControlRunnable final : public WorkerControlRunnable { } // namespace -// ---------------------------------------------------------------------------- -// WorkerRef::Holder - -class WorkerRef::Holder final : public mozilla::dom::WorkerHolder { - public: - Holder(const char* aName, WorkerRef* aWorkerRef, Behavior aBehavior) - : mozilla::dom::WorkerHolder(aName, aBehavior), mWorkerRef(aWorkerRef) {} - - bool Notify(WorkerStatus aStatus) override { - MOZ_ASSERT(mWorkerRef); - - if (aStatus < Canceling) { - return true; - } - - // Let's keep this object alive for the whole Notify() execution. - RefPtr workerRef; - workerRef = mWorkerRef; - - workerRef->Notify(); - return true; - } - - public: - WorkerRef* mWorkerRef; -}; - // ---------------------------------------------------------------------------- // WorkerRef -WorkerRef::WorkerRef(WorkerPrivate* aWorkerPrivate) - : mWorkerPrivate(aWorkerPrivate) { +WorkerRef::WorkerRef(WorkerPrivate* aWorkerPrivate, const char* aName, + bool aIsPreventingShutdown) + : mWorkerPrivate(aWorkerPrivate), + mName(aName), + mIsPreventingShutdown(aIsPreventingShutdown), + mHolding(false) { MOZ_ASSERT(aWorkerPrivate); + MOZ_ASSERT(aName); + aWorkerPrivate->AssertIsOnWorkerThread(); } -WorkerRef::~WorkerRef() { NS_ASSERT_OWNINGTHREAD(WorkerRef); } +WorkerRef::~WorkerRef() { + NS_ASSERT_OWNINGTHREAD(WorkerRef); + ReleaseWorker(); +} + +void WorkerRef::ReleaseWorker() { + if (mHolding) { + MOZ_ASSERT(mWorkerPrivate); + + mWorkerPrivate->RemoveWorkerRef(this); + mWorkerPrivate = nullptr; + + mHolding = false; + } +} + +bool WorkerRef::HoldWorker(WorkerStatus aStatus) { + MOZ_ASSERT(mWorkerPrivate); + MOZ_ASSERT(!mHolding); + + if (NS_WARN_IF(!mWorkerPrivate->AddWorkerRef(this, aStatus))) { + return false; + } + + mHolding = true; + return true; +} void WorkerRef::Notify() { - MOZ_ASSERT(mHolder); NS_ASSERT_OWNINGTHREAD(WorkerRef); if (!mCallback) { @@ -105,30 +108,30 @@ already_AddRefed WeakWorkerRef::Create( aWorkerPrivate->AssertIsOnWorkerThread(); RefPtr ref = new WeakWorkerRef(aWorkerPrivate); - - // This holder doesn't keep the worker alive. - UniquePtr holder(new Holder("WeakWorkerRef::Holder", ref, - WorkerHolder::AllowIdleShutdownStart)); - if (NS_WARN_IF(!holder->HoldWorker(aWorkerPrivate, Canceling))) { + if (!ref->HoldWorker(Canceling)) { return nullptr; } - ref->mHolder = std::move(holder); ref->mCallback = std::move(aCallback); return ref.forget(); } WeakWorkerRef::WeakWorkerRef(WorkerPrivate* aWorkerPrivate) - : WorkerRef(aWorkerPrivate) {} + : WorkerRef(aWorkerPrivate, "WeakWorkerRef", false) {} WeakWorkerRef::~WeakWorkerRef() = default; void WeakWorkerRef::Notify() { - WorkerRef::Notify(); + MOZ_ASSERT(mHolding); + MOZ_ASSERT(mWorkerPrivate); - mHolder = nullptr; - mWorkerPrivate = nullptr; + // Notify could drop the last reference to this object. We must keep it alive + // in order to call ReleaseWorker() immediately after. + RefPtr kungFuGrip = this; + + WorkerRef::Notify(); + ReleaseWorker(); } WorkerPrivate* WeakWorkerRef::GetPrivate() const { @@ -168,27 +171,21 @@ already_AddRefed StrongWorkerRef::CreateImpl( MOZ_ASSERT(aWorkerPrivate); MOZ_ASSERT(aName); - RefPtr ref = new StrongWorkerRef(aWorkerPrivate); - - // The worker is kept alive by this holder. - UniquePtr holder( - new Holder(aName, ref, WorkerHolder::PreventIdleShutdownStart)); - if (NS_WARN_IF(!holder->HoldWorker(aWorkerPrivate, aFailStatus))) { + RefPtr ref = new StrongWorkerRef(aWorkerPrivate, aName); + if (!ref->HoldWorker(aFailStatus)) { return nullptr; } - ref->mHolder = std::move(holder); - return ref.forget(); } -StrongWorkerRef::StrongWorkerRef(WorkerPrivate* aWorkerPrivate) - : WorkerRef(aWorkerPrivate) {} +StrongWorkerRef::StrongWorkerRef(WorkerPrivate* aWorkerPrivate, + const char* aName) + : WorkerRef(aWorkerPrivate, aName, true) {} -StrongWorkerRef::~StrongWorkerRef() { NS_ASSERT_OWNINGTHREAD(StrongWorkerRef); } +StrongWorkerRef::~StrongWorkerRef() = default; WorkerPrivate* StrongWorkerRef::Private() const { - MOZ_ASSERT(mHolder); NS_ASSERT_OWNINGTHREAD(StrongWorkerRef); return mWorkerPrivate; } @@ -216,5 +213,35 @@ WorkerPrivate* ThreadSafeWorkerRef::Private() const { return mRef->mWorkerPrivate; } +// ---------------------------------------------------------------------------- +// IPCWorkerRef + +/* static */ +already_AddRefed IPCWorkerRef::Create( + WorkerPrivate* aWorkerPrivate, const char* aName, + std::function&& aCallback) { + MOZ_ASSERT(aWorkerPrivate); + aWorkerPrivate->AssertIsOnWorkerThread(); + + RefPtr ref = new IPCWorkerRef(aWorkerPrivate, aName); + if (!ref->HoldWorker(Canceling)) { + return nullptr; + } + + ref->mCallback = std::move(aCallback); + + return ref.forget(); +} + +IPCWorkerRef::IPCWorkerRef(WorkerPrivate* aWorkerPrivate, const char* aName) + : WorkerRef(aWorkerPrivate, aName, false) {} + +IPCWorkerRef::~IPCWorkerRef() = default; + +WorkerPrivate* IPCWorkerRef::Private() const { + NS_ASSERT_OWNINGTHREAD(IPCWorkerRef); + return mWorkerPrivate; +} + } // namespace dom } // namespace mozilla diff --git a/dom/workers/WorkerRef.h b/dom/workers/WorkerRef.h index fa42a452962e..489cdca02268 100644 --- a/dom/workers/WorkerRef.h +++ b/dom/workers/WorkerRef.h @@ -8,7 +8,7 @@ #define mozilla_dom_workers_WorkerRef_h #include "mozilla/dom/WorkerCommon.h" -#include "mozilla/dom/WorkerHolder.h" +#include "mozilla/dom/WorkerStatus.h" #include "mozilla/UniquePtr.h" #include @@ -30,7 +30,7 @@ namespace dom { * d. Firefox is shutting down. * * When a DOM Worker goes away, it does several steps. See more in - * WorkerHolder.h. The DOM Worker thread will basically stop scheduling + * WorkerStatus.h. The DOM Worker thread will basically stop scheduling * WorkerRunnables, and eventually WorkerControlRunnables. But if there is * something preventing the shutting down, it will always possible to dispatch * WorkerControlRunnables. Of course, at some point, the worker _must_ be @@ -79,6 +79,23 @@ namespace dom { * ThreadSafeWorkerRef can be destroyed in any thread. Internally it keeps a * reference to its StrongWorkerRef creator and this ref will be dropped on the * correct thread when the ThreadSafeWorkerRef is deleted. + * + * IPC WorkerRef + * ~~~~~~~~~~~~~ + * + * IPDL protocols require a correct shutdown sequence. Because of this, they + * need a special configuration: + * 1. they need to be informed when the Worker starts the shutting down + * 2. they don't want to prevent the shutdown + * 3. but at the same time, they need to block the shutdown until the WorkerRef + * is not longer alive. + * + * Point 1 is a standard feature of WorkerRef; point 2 is similar to + * WeakWorkerRef; point 3 is similar to StrongWorkerRef. + * + * You can create a special IPC WorkerRef using this static method: + * mozilla::dom::IPCWorkerRef::Create(WorkerPrivate* aWorkerPrivate, + * const char* * aName); */ class WorkerPrivate; @@ -86,22 +103,33 @@ class StrongWorkerRef; class ThreadSafeWorkerRef; class WorkerRef { + friend class WorkerPrivate; + public: NS_INLINE_DECL_REFCOUNTING(WorkerRef) protected: - class Holder; - friend class Holder; - - explicit WorkerRef(WorkerPrivate* aWorkerPrivate); + WorkerRef(WorkerPrivate* aWorkerPrivate, const char* aName, + bool aIsPreventingShutdown); virtual ~WorkerRef(); virtual void Notify(); + bool HoldWorker(WorkerStatus aStatus); + void ReleaseWorker(); + + bool IsPreventingShutdown() const { return mIsPreventingShutdown; } + + const char* Name() const { return mName; } + WorkerPrivate* mWorkerPrivate; - UniquePtr mHolder; std::function mCallback; + const char* const mName; + const bool mIsPreventingShutdown; + + // True if this WorkerRef has been added to a WorkerPrivate. + bool mHolding; }; class WeakWorkerRef final : public WorkerRef { @@ -154,7 +182,7 @@ class StrongWorkerRef final : public WorkerRef { WorkerPrivate* aWorkerPrivate, const char* aName, WorkerStatus aFailStatus); - explicit StrongWorkerRef(WorkerPrivate* aWorkerPrivate); + StrongWorkerRef(WorkerPrivate* aWorkerPrivate, const char* aName); ~StrongWorkerRef(); }; @@ -174,6 +202,37 @@ class ThreadSafeWorkerRef final { RefPtr mRef; }; +class IPCWorkerRef final : public WorkerRef { + public: + static already_AddRefed Create( + WorkerPrivate* aWorkerPrivate, const char* aName, + std::function&& aCallback = nullptr); + + WorkerPrivate* Private() const; + + private: + IPCWorkerRef(WorkerPrivate* aWorkerPrivate, const char* aName); + ~IPCWorkerRef(); +}; + +// Template class to keep an Actor pointer, as a raw pointer, in a ref-counted +// way when passed to lambdas. +template +class IPCWorkerRefHelper final { + public: + NS_INLINE_DECL_REFCOUNTING(IPCWorkerRefHelper); + + explicit IPCWorkerRefHelper(ActorPtr* aActor) : mActor(aActor) {} + + ActorPtr* Actor() const { return mActor; } + + private: + ~IPCWorkerRefHelper() = default; + + // Raw pointer + ActorPtr* mActor; +}; + } // namespace dom } // namespace mozilla diff --git a/dom/workers/WorkerRunnable.h b/dom/workers/WorkerRunnable.h index 786b8c6d2482..46cc0d283627 100644 --- a/dom/workers/WorkerRunnable.h +++ b/dom/workers/WorkerRunnable.h @@ -9,6 +9,7 @@ #include "mozilla/dom/WorkerCommon.h" #include "mozilla/dom/WorkerRef.h" +#include "mozilla/dom/WorkerStatus.h" #include "nsICancelableRunnable.h" diff --git a/dom/workers/WorkerHolder.h b/dom/workers/WorkerStatus.h similarity index 63% rename from dom/workers/WorkerHolder.h rename to dom/workers/WorkerStatus.h index 263c8c5a358a..b257b2d2afa5 100644 --- a/dom/workers/WorkerHolder.h +++ b/dom/workers/WorkerStatus.h @@ -4,16 +4,12 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#ifndef mozilla_dom_workers_WorkerHolder_h -#define mozilla_dom_workers_WorkerHolder_h - -#include "mozilla/dom/WorkerCommon.h" +#ifndef mozilla_dom_workers_WorkerStatus_h +#define mozilla_dom_workers_WorkerStatus_h namespace mozilla { namespace dom { -class WorkerPrivate; - /** * Use this chart to help figure out behavior during each of the closing * statuses. Details below. @@ -40,9 +36,9 @@ enum WorkerStatus { // Inner script called close() on the worker global scope. Setting this // status causes the worker to clear its queue of events but does not abort - // the currently running script. WorkerHolder/WorkerRef objects are not going - // to be notified because the behavior of APIs/Components should not change - // during this status yet. + // the currently running script. WorkerRef objects are not going to be + // notified because the behavior of APIs/Components should not change during + // this status yet. Closing, // Either the user navigated away from the owning page or the owning page fell @@ -58,42 +54,7 @@ enum WorkerStatus { Dead }; -class WorkerHolder { - public: - enum Behavior { - AllowIdleShutdownStart, - PreventIdleShutdownStart, - }; - - explicit WorkerHolder(const char* aName, - Behavior aBehavior = PreventIdleShutdownStart); - virtual ~WorkerHolder(); - - bool HoldWorker(WorkerPrivate* aWorkerPrivate, WorkerStatus aFailStatus); - void ReleaseWorker(); - - virtual bool Notify(WorkerStatus aStatus) = 0; - - Behavior GetBehavior() const; - - const char* Name() const { return mName; } - - protected: - void ReleaseWorkerInternal(); - - WorkerPrivate* MOZ_NON_OWNING_REF mWorkerPrivate; - - private: - void AssertIsOwningThread() const; - - const Behavior mBehavior; - - // For debugging only. - void* mThread; - const char* mName; -}; - } // namespace dom } // namespace mozilla -#endif /* mozilla_dom_workers_WorkerHolder_h */ +#endif /* mozilla_dom_workers_WorkerStatus_h */ diff --git a/dom/workers/moz.build b/dom/workers/moz.build index c4b17fc67983..0587d7ab639e 100644 --- a/dom/workers/moz.build +++ b/dom/workers/moz.build @@ -17,8 +17,6 @@ EXPORTS.mozilla.dom += [ 'WorkerDebugger.h', 'WorkerDebuggerManager.h', 'WorkerError.h', - 'WorkerHolder.h', - 'WorkerHolderToken.h', 'WorkerLoadInfo.h', 'WorkerLocation.h', 'WorkerNavigator.h', @@ -26,6 +24,7 @@ EXPORTS.mozilla.dom += [ 'WorkerRef.h', 'WorkerRunnable.h', 'WorkerScope.h', + 'WorkerStatus.h', ] # Private stuff. @@ -57,8 +56,6 @@ UNIFIED_SOURCES += [ 'WorkerDebuggerManager.cpp', 'WorkerError.cpp', 'WorkerEventTarget.cpp', - 'WorkerHolder.cpp', - 'WorkerHolderToken.cpp', 'WorkerLoadInfo.cpp', 'WorkerLocation.cpp', 'WorkerNavigator.cpp', diff --git a/gfx/webrender_bindings/src/moz2d_renderer.rs b/gfx/webrender_bindings/src/moz2d_renderer.rs index d858a3954845..6f0aa92a794b 100644 --- a/gfx/webrender_bindings/src/moz2d_renderer.rs +++ b/gfx/webrender_bindings/src/moz2d_renderer.rs @@ -77,11 +77,10 @@ pub struct Moz2dBlobImageHandler { /// Transmute some bytes into a value. /// -/// Wow this is dangerous if non-POD values are read! /// FIXME: kill this with fire and/or do a super robust security audit -unsafe fn convert_from_bytes(slice: &[u8]) -> T { +unsafe fn convert_from_bytes(slice: &[u8]) -> T { assert!(mem::size_of::() <= slice.len()); - ptr::read(slice.as_ptr() as *const T) + ptr::read_unaligned(slice.as_ptr() as *const T) } /// Transmute a value into some bytes. @@ -113,7 +112,7 @@ impl<'a> BufReader<'a> { /// /// To limit the scope of this unsafety, please don't call this directly. /// Make a helper method for each whitelisted type. - unsafe fn read(&mut self) -> T { + unsafe fn read(&mut self) -> T { let ret = convert_from_bytes(&self.buf[self.pos..]); self.pos += mem::size_of::(); ret @@ -419,6 +418,7 @@ fn merge_blob_images(old_buf: &[u8], new_buf: &[u8], dirty_rect: Box2d) -> Vec" +"checksum serde_derive 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)" = "beed18e6f5175aef3ba670e57c60ef3b1b74d250d962a26604bff4c80e970dd4" "checksum serde_json 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)" = "f3ad6d546e765177cf3dded3c2e424a8040f870083a0e64064746b958ece9cb1" "checksum servo-fontconfig 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a088f8d775a5c5314aae09bd77340bc9c67d72b9a45258be34c83548b4814cd9" "checksum servo-fontconfig-sys 4.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "38b494f03009ee81914b0e7d387ad7c145cafcd69747c2ec89b0e17bb94f303a" diff --git a/gfx/wr/Cargo.toml b/gfx/wr/Cargo.toml index 6cef51cf0643..a13cc5674cee 100644 --- a/gfx/wr/Cargo.toml +++ b/gfx/wr/Cargo.toml @@ -13,6 +13,3 @@ panic = "abort" [profile.dev] panic = "abort" - -[patch.crates-io] -serde_derive = { git = "https://github.com/servo/serde", branch = "deserialize_from_enums10" } diff --git a/gfx/wr/peek-poke/Cargo.toml b/gfx/wr/peek-poke/Cargo.toml new file mode 100644 index 000000000000..16e20b93063f --- /dev/null +++ b/gfx/wr/peek-poke/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "peek-poke" +version = "0.2.0" +authors = ["Dan Glastonbury "] +license = "MIT/Apache-2.0" +edition = "2018" + +[dependencies] +euclid = { version = "0.19", optional = true } +peek-poke-derive = { version = "0.2", path = "./peek-poke-derive", optional = true } + +[features] +default = ["derive"] +derive = ["peek-poke-derive"] +extras = ["derive", "euclid"] diff --git a/gfx/wr/peek-poke/LICENSE-APACHE b/gfx/wr/peek-poke/LICENSE-APACHE new file mode 100644 index 000000000000..16fe87b06e80 --- /dev/null +++ b/gfx/wr/peek-poke/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/gfx/wr/peek-poke/LICENSE-MIT b/gfx/wr/peek-poke/LICENSE-MIT new file mode 100644 index 000000000000..110bb347123f --- /dev/null +++ b/gfx/wr/peek-poke/LICENSE-MIT @@ -0,0 +1,44 @@ +MIT License + +Copyright (c) 2019 Daniel Glastonbury + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +This work incorporates work covered by the following copyright and permission +notice: + +Copyright (c) 2019 Devashish Dixit + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/gfx/wr/peek-poke/README.md b/gfx/wr/peek-poke/README.md new file mode 100644 index 000000000000..1c379aa1211f --- /dev/null +++ b/gfx/wr/peek-poke/README.md @@ -0,0 +1,54 @@ +# Peeks, Pokes, and Pointers + +Peek from and poke structures into byte slices. + +## Benchmark + +Below are the benchmark results of comparison between `peek-poke` and `bincode` serializing and deserializing same `struct`: +``` +struct MyPeekPokeStruct { + a: u8, + b: u16, + c: MyPeekPokeEnum, + d: Option, +} + +enum MyPeekPokeEnum { + Variant1, + Variant2(u16), +} +``` + +``` +Benchmarking struct::serialize/peek_poke::poke_into: Collecting 100 samples in struct::serialize/peek_poke::poke_into + time: [2.7267 ns 2.7321 ns 2.7380 ns] + +Benchmarking struct::serialize/bincode::serialize: Collecting 100 samples in est struct::serialize/bincode::serialize + time: [31.264 ns 31.326 ns 31.389 ns] + +Benchmarking struct::deserialize/peek_poke::peek_from: Collecting 100 samples struct::deserialize/peek_poke::peek_from + time: [5.3544 ns 5.3672 ns 5.3817 ns] + +Benchmarking struct::deserialize/bincode::deserialize: Collecting 100 samples in struct::deserialize/bincode::deserialize + time: [25.155 ns 26.439 ns 27.661 ns] +``` + +You can run benchmarks by running following command: +``` +cargo bench +``` + +## License +[license]: #license + +Licensed under either of +- Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) +- MIT license (http://opensource.org/licenses/MIT) + +at your option. + +see [LICENSE-APACHE](LICENSE-APACHE), [LICENSE-MIT](LICENSE-MIT) for details. + +## Contribution +Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as +defined in the Apache-2.0 license, shall be dual licensed as about, without any additional terms or conditions. diff --git a/gfx/wr/peek-poke/peek-poke-derive/Cargo.toml b/gfx/wr/peek-poke/peek-poke-derive/Cargo.toml new file mode 100644 index 000000000000..02b27c57472b --- /dev/null +++ b/gfx/wr/peek-poke/peek-poke-derive/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "peek-poke-derive" +version = "0.2.0" +authors = ["Dan Glastonbury "] +license = "MIT/Apache-2.0" +edition = "2018" + +[lib] +doctest = false +proc-macro = true + +[dependencies] +proc-macro2 = "0.4" +quote = "0.6" +syn = "0.15" +synstructure = "0.10" +unicode-xid = "0.1" diff --git a/gfx/wr/peek-poke/peek-poke-derive/LICENSE-APACHE b/gfx/wr/peek-poke/peek-poke-derive/LICENSE-APACHE new file mode 100644 index 000000000000..16fe87b06e80 --- /dev/null +++ b/gfx/wr/peek-poke/peek-poke-derive/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/gfx/wr/peek-poke/peek-poke-derive/LICENSE-MIT b/gfx/wr/peek-poke/peek-poke-derive/LICENSE-MIT new file mode 100644 index 000000000000..110bb347123f --- /dev/null +++ b/gfx/wr/peek-poke/peek-poke-derive/LICENSE-MIT @@ -0,0 +1,44 @@ +MIT License + +Copyright (c) 2019 Daniel Glastonbury + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +This work incorporates work covered by the following copyright and permission +notice: + +Copyright (c) 2019 Devashish Dixit + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/gfx/wr/peek-poke/peek-poke-derive/README.md b/gfx/wr/peek-poke/peek-poke-derive/README.md new file mode 100644 index 000000000000..1c379aa1211f --- /dev/null +++ b/gfx/wr/peek-poke/peek-poke-derive/README.md @@ -0,0 +1,54 @@ +# Peeks, Pokes, and Pointers + +Peek from and poke structures into byte slices. + +## Benchmark + +Below are the benchmark results of comparison between `peek-poke` and `bincode` serializing and deserializing same `struct`: +``` +struct MyPeekPokeStruct { + a: u8, + b: u16, + c: MyPeekPokeEnum, + d: Option, +} + +enum MyPeekPokeEnum { + Variant1, + Variant2(u16), +} +``` + +``` +Benchmarking struct::serialize/peek_poke::poke_into: Collecting 100 samples in struct::serialize/peek_poke::poke_into + time: [2.7267 ns 2.7321 ns 2.7380 ns] + +Benchmarking struct::serialize/bincode::serialize: Collecting 100 samples in est struct::serialize/bincode::serialize + time: [31.264 ns 31.326 ns 31.389 ns] + +Benchmarking struct::deserialize/peek_poke::peek_from: Collecting 100 samples struct::deserialize/peek_poke::peek_from + time: [5.3544 ns 5.3672 ns 5.3817 ns] + +Benchmarking struct::deserialize/bincode::deserialize: Collecting 100 samples in struct::deserialize/bincode::deserialize + time: [25.155 ns 26.439 ns 27.661 ns] +``` + +You can run benchmarks by running following command: +``` +cargo bench +``` + +## License +[license]: #license + +Licensed under either of +- Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) +- MIT license (http://opensource.org/licenses/MIT) + +at your option. + +see [LICENSE-APACHE](LICENSE-APACHE), [LICENSE-MIT](LICENSE-MIT) for details. + +## Contribution +Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as +defined in the Apache-2.0 license, shall be dual licensed as about, without any additional terms or conditions. diff --git a/gfx/wr/peek-poke/peek-poke-derive/src/lib.rs b/gfx/wr/peek-poke/peek-poke-derive/src/lib.rs new file mode 100644 index 000000000000..ead00921628b --- /dev/null +++ b/gfx/wr/peek-poke/peek-poke-derive/src/lib.rs @@ -0,0 +1,259 @@ +// Copyright 2019 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use proc_macro2::{Span, TokenStream}; +use quote::quote; +use syn::{Ident, Index, TraitBound}; +use synstructure::{decl_derive, Structure, BindStyle, AddBounds}; +use unicode_xid::UnicodeXID; + +// Internal method for sanitizing an identifier for hygiene purposes. +fn sanitize_ident(s: &str) -> Ident { + let mut res = String::with_capacity(s.len()); + for mut c in s.chars() { + if !UnicodeXID::is_xid_continue(c) { + c = '_' + } + // Deduplicate consecutive _ characters. + if res.ends_with('_') && c == '_' { + continue; + } + res.push(c); + } + Ident::new(&res, Span::call_site()) +} + +/// Calculates size type for number of variants (used for enums) +fn get_discriminant_size_type(len: usize) -> TokenStream { + if len <= ::max_value() as usize { + quote! { u8 } + } else if len <= ::max_value() as usize { + quote! { u16 } + } else { + quote! { u32 } + } +} + +fn is_struct(s: &Structure) -> bool { + // a single variant with no prefix is 'struct' + match &s.variants()[..] { + [v] if v.prefix.is_none() => true, + _ => false, + } +} + +fn derive_max_size(s: &Structure) -> TokenStream { + let max_size = s.variants().iter().fold(quote!(0), |acc, vi| { + let variant_size = vi.bindings().iter().fold(quote!(0), |acc, bi| { + // compute size of each variant by summing the sizes of its bindings + let ty = &bi.ast().ty; + quote!(#acc + <#ty>::max_size()) + }); + + // find the maximum of each variant + quote! { + max(#acc, #variant_size) + } + }); + + let body = if is_struct(s) { + max_size + } else { + let discriminant_size_type = get_discriminant_size_type(s.variants().len()); + quote! { + #discriminant_size_type ::max_size() + #max_size + } + }; + + quote! { + #[inline(always)] + fn max_size() -> usize { + use std::cmp::max; + #body + } + } +} + +fn derive_peek_from_for_enum(s: &mut Structure) -> TokenStream { + assert!(!is_struct(s)); + s.bind_with(|_| BindStyle::Move); + + let discriminant_size_type = get_discriminant_size_type(s.variants().len()); + let body = s + .variants() + .iter() + .enumerate() + .fold(quote!(), |acc, (i, vi)| { + let bindings = vi + .bindings() + .iter() + .map(|bi| quote!(#bi)) + .collect::>(); + + let variant_pat = Index::from(i); + let poke_exprs = bindings.iter().fold(quote!(), |acc, bi| { + quote! { + #acc + let (#bi, bytes) = peek_poke::peek_from_default(bytes); + } + }); + let construct = vi.construct(|_, i| { + let bi = &bindings[i]; + quote!(#bi) + }); + + quote! { + #acc + #variant_pat => { + #poke_exprs + *output = #construct; + bytes + } + } + }); + + quote! { + #[inline(always)] + unsafe fn peek_from(bytes: *const u8, output: *mut Self) -> *const u8 { + let (variant, bytes) = peek_poke::peek_from_default::<#discriminant_size_type>(bytes); + match variant { + #body + _ => unreachable!() + } + } + } +} + +fn derive_peek_from_for_struct(s: &mut Structure) -> TokenStream { + assert!(is_struct(&s)); + + s.variants_mut()[0].bind_with(|_| BindStyle::RefMut); + let pat = s.variants()[0].pat(); + let peek_exprs = s.variants()[0].bindings().iter().fold(quote!(), |acc, bi| { + let ty = &bi.ast().ty; + quote! { + #acc + let bytes = <#ty>::peek_from(bytes, #bi); + } + }); + + let body = quote! { + #pat => { + #peek_exprs + bytes + } + }; + + quote! { + #[inline(always)] + unsafe fn peek_from(bytes: *const u8, output: *mut Self) -> *const u8 { + match &mut (*output) { + #body + } + } + } +} + +fn derive_poke_into(s: &Structure) -> TokenStream { + let is_struct = is_struct(&s); + let discriminant_size_type = get_discriminant_size_type(s.variants().len()); + let body = s + .variants() + .iter() + .enumerate() + .fold(quote!(), |acc, (i, vi)| { + let init = if !is_struct { + let index = Index::from(i); + quote! { + let bytes = #discriminant_size_type::poke_into(&#index, bytes); + } + } else { + quote!() + }; + let variant_pat = vi.pat(); + let poke_exprs = vi.bindings().iter().fold(init, |acc, bi| { + quote! { + #acc + let bytes = #bi.poke_into(bytes); + } + }); + + quote! { + #acc + #variant_pat => { + #poke_exprs + bytes + } + } + }); + + quote! { + #[inline(always)] + unsafe fn poke_into(&self, bytes: *mut u8) -> *mut u8 { + match &*self { + #body + } + } + } +} + +fn peek_poke_derive(mut s: Structure) -> TokenStream { + s.binding_name(|_, i| Ident::new(&format!("__self_{}", i), Span::call_site())); + + let max_size_fn = derive_max_size(&s); + let poke_into_fn = derive_poke_into(&s); + let peek_from_fn = if is_struct(&s) { + derive_peek_from_for_struct(&mut s) + } else { + derive_peek_from_for_enum(&mut s) + }; + + let poke_impl = s.gen_impl(quote! { + extern crate peek_poke; + + gen unsafe impl peek_poke::Poke for @Self { + #max_size_fn + #poke_into_fn + } + }); + + // To implement `fn peek_from` we require that types implement `Default` + // trait to create temporary values. This code does the addition all + // manually until https://github.com/mystor/synstructure/issues/24 is fixed. + let default_trait = syn::parse_str::("::std::default::Default").unwrap(); + let peek_trait = syn::parse_str::("peek_poke::Peek").unwrap(); + + let ast = s.ast(); + let name = &ast.ident; + let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl(); + let mut where_clause = where_clause.cloned(); + s.add_trait_bounds(&default_trait, &mut where_clause, AddBounds::Generics); + s.add_trait_bounds(&peek_trait, &mut where_clause, AddBounds::Generics); + + let dummy_const: Ident = sanitize_ident(&format!("_DERIVE_peek_poke_Peek_FOR_{}", name)); + + let peek_impl = quote! { + #[allow(non_upper_case_globals)] + const #dummy_const: () = { + extern crate peek_poke; + + impl #impl_generics peek_poke::Peek for #name #ty_generics #where_clause { + #peek_from_fn + } + }; + }; + + quote! { + #poke_impl + #peek_impl + } +} + +decl_derive!([PeekPoke] => peek_poke_derive); diff --git a/gfx/wr/peek-poke/src/euclid.rs b/gfx/wr/peek-poke/src/euclid.rs new file mode 100644 index 000000000000..b007701a2812 --- /dev/null +++ b/gfx/wr/peek-poke/src/euclid.rs @@ -0,0 +1,170 @@ +// Copyright 2019 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use crate::{Peek, Poke}; +use euclid::{TypedPoint2D, TypedRect, TypedSideOffsets2D, TypedSize2D, TypedTransform3D, TypedVector2D}; + +unsafe impl Poke for TypedPoint2D { + #[inline(always)] + fn max_size() -> usize { + 2 * T::max_size() + } + #[inline(always)] + unsafe fn poke_into(&self, bytes: *mut u8) -> *mut u8 { + let bytes = self.x.poke_into(bytes); + let bytes = self.y.poke_into(bytes); + bytes + } +} +impl Peek for TypedPoint2D { + #[inline(always)] + unsafe fn peek_from(bytes: *const u8, output: *mut Self) -> *const u8 { + let bytes = T::peek_from(bytes, &mut (*output).x); + let bytes = T::peek_from(bytes, &mut (*output).y); + bytes + } +} + +unsafe impl Poke for TypedRect { + #[inline(always)] + fn max_size() -> usize { + TypedPoint2D::::max_size() + TypedSize2D::::max_size() + } + #[inline(always)] + unsafe fn poke_into(&self, bytes: *mut u8) -> *mut u8 { + let bytes = self.origin.poke_into(bytes); + let bytes = self.size.poke_into(bytes); + bytes + } +} +impl Peek for TypedRect { + #[inline(always)] + unsafe fn peek_from(bytes: *const u8, output: *mut Self) -> *const u8 { + let bytes = TypedPoint2D::::peek_from(bytes, &mut (*output).origin); + let bytes = TypedSize2D::::peek_from(bytes, &mut (*output).size); + bytes + } +} + +unsafe impl Poke for TypedSideOffsets2D { + #[inline(always)] + fn max_size() -> usize { + 4 * T::max_size() + } + #[inline(always)] + unsafe fn poke_into(&self, bytes: *mut u8) -> *mut u8 { + let bytes = self.top.poke_into(bytes); + let bytes = self.right.poke_into(bytes); + let bytes = self.bottom.poke_into(bytes); + let bytes = self.left.poke_into(bytes); + bytes + } +} +impl Peek for TypedSideOffsets2D { + #[inline(always)] + unsafe fn peek_from(bytes: *const u8, output: *mut Self) -> *const u8 { + let bytes = T::peek_from(bytes, &mut (*output).top); + let bytes = T::peek_from(bytes, &mut (*output).right); + let bytes = T::peek_from(bytes, &mut (*output).bottom); + let bytes = T::peek_from(bytes, &mut (*output).left); + bytes + } +} + +unsafe impl Poke for TypedSize2D { + #[inline(always)] + fn max_size() -> usize { + 2 * T::max_size() + } + #[inline(always)] + unsafe fn poke_into(&self, bytes: *mut u8) -> *mut u8 { + let bytes = self.width.poke_into(bytes); + let bytes = self.height.poke_into(bytes); + bytes + } +} +impl Peek for TypedSize2D { + #[inline(always)] + unsafe fn peek_from(bytes: *const u8, output: *mut Self) -> *const u8 { + let bytes = T::peek_from(bytes, &mut (*output).width); + let bytes = T::peek_from(bytes, &mut (*output).height); + bytes + } +} + +unsafe impl Poke for TypedTransform3D { + #[inline(always)] + fn max_size() -> usize { + 16 * T::max_size() + } + #[inline(always)] + unsafe fn poke_into(&self, bytes: *mut u8) -> *mut u8 { + let bytes = self.m11.poke_into(bytes); + let bytes = self.m12.poke_into(bytes); + let bytes = self.m13.poke_into(bytes); + let bytes = self.m14.poke_into(bytes); + let bytes = self.m21.poke_into(bytes); + let bytes = self.m22.poke_into(bytes); + let bytes = self.m23.poke_into(bytes); + let bytes = self.m24.poke_into(bytes); + let bytes = self.m31.poke_into(bytes); + let bytes = self.m32.poke_into(bytes); + let bytes = self.m33.poke_into(bytes); + let bytes = self.m34.poke_into(bytes); + let bytes = self.m41.poke_into(bytes); + let bytes = self.m42.poke_into(bytes); + let bytes = self.m43.poke_into(bytes); + let bytes = self.m44.poke_into(bytes); + bytes + } +} +impl Peek for TypedTransform3D { + #[inline(always)] + unsafe fn peek_from(bytes: *const u8, output: *mut Self) -> *const u8 { + let bytes = T::peek_from(bytes, &mut (*output).m11); + let bytes = T::peek_from(bytes, &mut (*output).m12); + let bytes = T::peek_from(bytes, &mut (*output).m13); + let bytes = T::peek_from(bytes, &mut (*output).m14); + let bytes = T::peek_from(bytes, &mut (*output).m21); + let bytes = T::peek_from(bytes, &mut (*output).m22); + let bytes = T::peek_from(bytes, &mut (*output).m23); + let bytes = T::peek_from(bytes, &mut (*output).m24); + let bytes = T::peek_from(bytes, &mut (*output).m31); + let bytes = T::peek_from(bytes, &mut (*output).m32); + let bytes = T::peek_from(bytes, &mut (*output).m33); + let bytes = T::peek_from(bytes, &mut (*output).m34); + let bytes = T::peek_from(bytes, &mut (*output).m41); + let bytes = T::peek_from(bytes, &mut (*output).m42); + let bytes = T::peek_from(bytes, &mut (*output).m43); + let bytes = T::peek_from(bytes, &mut (*output).m44); + bytes + } +} + +unsafe impl Poke for TypedVector2D { + #[inline(always)] + fn max_size() -> usize { + 2 * T::max_size() + } + #[inline(always)] + unsafe fn poke_into(&self, bytes: *mut u8) -> *mut u8 { + let bytes = self.x.poke_into(bytes); + let bytes = self.y.poke_into(bytes); + bytes + } +} +impl Peek for TypedVector2D { + #[inline(always)] + unsafe fn peek_from(bytes: *const u8, output: *mut Self) -> *const u8 { + let bytes = T::peek_from(bytes, &mut (*output).x); + let bytes = T::peek_from(bytes, &mut (*output).y); + bytes + } +} diff --git a/gfx/wr/peek-poke/src/lib.rs b/gfx/wr/peek-poke/src/lib.rs new file mode 100644 index 000000000000..e308f327ff14 --- /dev/null +++ b/gfx/wr/peek-poke/src/lib.rs @@ -0,0 +1,427 @@ +// Copyright 2019 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Fast binary serialization and deserialization for types with a known maximum size. +//! +//! ## Binary Encoding Scheme +//! +//! ## Usage +//! +//! ## Comparison to bincode + +#[cfg(feature = "derive")] +pub use peek_poke_derive::*; + +use core::{marker::PhantomData, mem::size_of, slice}; +use crate::{slice_ext::*, vec_ext::*}; + +mod slice_ext; +mod vec_ext; + +union MaybeUninitShim { + uninit: (), + init: T, +} + +/// Peek helper for constructing a `T` by `Copy`ing into an uninitialized stack +/// allocation. +pub unsafe fn peek_from_uninit(bytes: *const u8) -> (T, *const u8) { + let mut val = MaybeUninitShim { uninit: () }; + let bytes = ::peek_from(bytes, &mut val.init); + (val.init, bytes) +} + +/// Peek helper for constructing a `T` by `Default` initialized stack +/// allocation. +pub unsafe fn peek_from_default(bytes: *const u8) -> (T, *const u8) { + let mut val = T::default(); + let bytes = ::peek_from(bytes, &mut val); + (val, bytes) +} + +/// Peek inplace a `T` from a slice of bytes, returning a slice of the remaining +/// bytes. `src` must contain at least `T::max_size()` bytes. +/// +/// [`ensure_red_zone`] can be used to add required padding. +pub fn peek_from_slice<'a, T: Peek>(src: &'a [u8], dst: &mut T) -> &'a [u8] { + unsafe { + // If src.len() == T::max_size() then src is at the start of the red-zone. + assert!(T::max_size() < src.len()); + let end_ptr = T::peek_from(src.as_ptr(), dst); + let len = end_ptr as usize - src.as_ptr() as usize; + // Did someone break the T::peek_from() can't read more than T::max_size() + // bytes contract? + assert!(len <= src.len()); + slice::from_raw_parts(end_ptr, src.len() - len) + } +} + +/// Poke helper to insert a serialized version of `src` at the beginning for `dst`. +pub fn poke_inplace_slice(src: &T, dst: &mut [u8]) { + assert!(T::max_size() <= dst.len()); + unsafe { + src.poke_into(dst.as_mut_ptr()); + } +} + +/// Poke helper to append a serialized version of `src` to the end of `dst`. +pub fn poke_into_vec(src: &T, dst: &mut Vec) { + dst.reserve(T::max_size()); + unsafe { + let ptr = dst.as_end_mut_ptr(); + let end_ptr = src.poke_into(ptr); + dst.set_end_ptr(end_ptr); + } +} + +// TODO: Is returning the len of the iterator of any practical use? +pub fn poke_extend_vec(src: I, dst: &mut Vec) -> usize +where + I: ExactSizeIterator, + I::Item: Poke, +{ + let len = src.len(); + let max_size = len * I::Item::max_size(); + dst.reserve(max_size); + unsafe { + let ptr = dst.as_end_mut_ptr(); + // Guard against the possibility of a misbehaved implementation of + // ExactSizeIterator by writing at most `len` items. + let end_ptr = src.take(len).fold(ptr, |ptr, item| item.poke_into(ptr)); + dst.set_end_ptr(end_ptr); + } + + len +} + +/// Add `T::max_size()` "red zone" (padding of zeroes) to the end of the vec of +/// `bytes`. This allows deserialization to assert that at least `T::max_size()` +/// bytes exist at all times. +pub fn ensure_red_zone(bytes: &mut Vec) { + bytes.reserve(T::max_size()); + unsafe { + let end_ptr = bytes.as_end_mut_ptr(); + end_ptr.write_bytes(0, T::max_size()); + bytes.set_end_ptr(end_ptr.add(T::max_size())); + } +} + +#[inline] +unsafe fn read_verbatim(src: *const u8, dst: *mut T) -> *const u8 { + *dst = (src as *const T).read_unaligned(); + src.add(size_of::()) +} + +#[inline] +unsafe fn write_verbatim(src: T, dst: *mut u8) -> *mut u8 { + (dst as *mut T).write_unaligned(src); + dst.add(size_of::()) +} + +#[cfg(feature = "extras")] +mod euclid; + +/// A trait for values that provide serialization into buffers of bytes. +/// +/// # Example +/// +/// ```no_run +/// use peek_poke::Poke; +/// +/// struct Bar { +/// a: u32, +/// b: u8, +/// c: i16, +/// } +/// +/// unsafe impl Poke for Bar { +/// fn max_size() -> usize { +/// ::max_size() + ::max_size() + ::max_size() +/// } +/// unsafe fn poke_into(&self, bytes: *mut u8) -> *mut u8 { +/// let bytes = self.a.poke_into(bytes); +/// let bytes = self.b.poke_into(bytes); +/// self.c.poke_into(bytes) +/// } +/// } +/// ``` +/// +/// # Safety +/// +/// The `Poke` trait is an `unsafe` trait for the reasons, and implementors must +/// ensure that they adhere to these contracts: +/// +/// * `max_size()` query and calculations in general must be correct. Callers +/// of this trait are expected to rely on the contract defined on each +/// method, and implementors must ensure such contracts remain true. +pub unsafe trait Poke { + /// Return the maximum number of bytes that the serialized version of `Self` + /// will occupy. + /// + /// # Safety + /// + /// Implementors of `Poke` guarantee to not write more than the result of + /// calling `max_size()` into the buffer pointed to by `bytes` when + /// `poke_into()` is called. + fn max_size() -> usize; + /// Serialize into the buffer pointed to by `bytes`. + /// + /// Returns a pointer to the next byte after the serialized representation of `Self`. + /// + /// # Safety + /// + /// This function is unsafe because undefined behavior can result if the + /// caller does not ensure all of the following: + /// + /// * `bytes` must denote a valid pointer to a block of memory. + /// + /// * `bytes` must pointer to at least the number of bytes returned by + /// `max_size()`. + unsafe fn poke_into(&self, bytes: *mut u8) -> *mut u8; +} + +/// A trait for values that provide deserialization from buffers of bytes. +/// +/// # Example +/// +/// ```ignore +/// use peek_poke::Peek; +/// +/// struct Bar { +/// a: u32, +/// b: u8, +/// c: i16, +/// } +/// +/// ... +/// +/// impl Peek for Bar { +/// unsafe fn peek_from(&mut self, bytes: *const u8) -> *const u8 { +/// let bytes = self.a.peek_from(bytes); +/// let bytes = self.b.peek_from(bytes); +/// self.c.peek_from(bytes) +/// } +/// } +/// ``` +/// +/// # Safety +/// +/// The `Peek` trait contains unsafe methods for the following reasons, and +/// implementors must ensure that they adhere to these contracts: +/// +/// * Callers of this trait are expected to rely on the contract defined on each +/// method, and implementors must ensure that `peek_from()` doesn't read more +/// bytes from `bytes` than is returned by `Peek::max_size()`. +pub trait Peek: Poke { + /// Deserialize from the buffer pointed to by `bytes`. + /// + /// Returns a pointer to the next byte after the unconsumed bytes not used + /// to deserialize the representation of `Self`. + /// + /// # Safety + /// + /// This function is unsafe because undefined behavior can result if the + /// caller does not ensure all of the following: + /// + /// * `bytes` must denote a valid pointer to a block of memory. + /// + /// * `bytes` must pointer to at least the number of bytes returned by + /// `Poke::max_size()`. + unsafe fn peek_from(bytes: *const u8, output: *mut Self) -> *const u8; +} + +macro_rules! impl_poke_for_deref { + (<$($desc:tt)+) => { + unsafe impl <$($desc)+ { + #[inline(always)] + fn max_size() -> usize { + ::max_size() + } + unsafe fn poke_into(&self, bytes: *mut u8) -> *mut u8 { + (**self).poke_into(bytes) + } + } + } +} + +impl_poke_for_deref!(<'a, T: Poke> Poke for &'a T); +impl_poke_for_deref!(<'a, T: Poke> Poke for &'a mut T); + +macro_rules! impl_for_primitive { + ($($ty:ty)+) => { + $(unsafe impl Poke for $ty { + #[inline(always)] + fn max_size() -> usize { + size_of::() + } + #[inline(always)] + unsafe fn poke_into(&self, bytes: *mut u8) -> *mut u8 { + write_verbatim(*self, bytes) + } + } + impl Peek for $ty { + #[inline(always)] + unsafe fn peek_from(bytes: *const u8, output: *mut Self) -> *const u8 { + read_verbatim(bytes, output) + } + })+ + }; +} + +impl_for_primitive! { + i8 i16 i32 i64 isize + u8 u16 u32 u64 usize + f32 f64 +} + +unsafe impl Poke for bool { + #[inline(always)] + fn max_size() -> usize { + u8::max_size() + } + #[inline] + unsafe fn poke_into(&self, bytes: *mut u8) -> *mut u8 { + (*self as u8).poke_into(bytes) + } +} + +impl Peek for bool { + #[inline] + unsafe fn peek_from(bytes: *const u8, output: *mut Self) -> *const u8 { + let mut int_bool = 0u8; + let ptr = ::peek_from(bytes, &mut int_bool); + *output = int_bool != 0; + ptr + } +} + +unsafe impl Poke for PhantomData { + #[inline(always)] + fn max_size() -> usize { + 0 + } + #[inline(always)] + unsafe fn poke_into(&self, bytes: *mut u8) -> *mut u8 { + bytes + } +} + +impl Peek for PhantomData { + #[inline(always)] + unsafe fn peek_from(bytes: *const u8, output: *mut Self) -> *const u8 { + *output = PhantomData; + bytes + } +} + +unsafe impl Poke for Option { + #[inline(always)] + fn max_size() -> usize { + u8::max_size() + T::max_size() + } + + #[inline] + unsafe fn poke_into(&self, bytes: *mut u8) -> *mut u8 { + match self { + None => 0u8.poke_into(bytes), + Some(ref v) => { + let bytes = 1u8.poke_into(bytes); + let bytes = v.poke_into(bytes); + bytes + } + } + } +} + +impl Peek for Option { + #[inline] + unsafe fn peek_from(bytes: *const u8, output: *mut Self) -> *const u8 { + let (variant, bytes) = peek_from_default::(bytes); + match variant { + 0 => { + *output = None; + bytes + } + 1 => { + let (val, bytes) = peek_from_default(bytes); + *output = Some(val); + bytes + } + _ => unreachable!(), + } + } +} + +macro_rules! impl_for_arrays { + ($($len:tt)+) => { + $(unsafe impl Poke for [T; $len] { + fn max_size() -> usize { + $len * T::max_size() + } + unsafe fn poke_into(&self, bytes: *mut u8) -> *mut u8 { + self.iter().fold(bytes, |bytes, e| e.poke_into(bytes)) + } + } + impl Peek for [T; $len] { + unsafe fn peek_from(bytes: *const u8, output: *mut Self) -> *const u8 { + (&mut *output).iter_mut().fold(bytes, |bytes, e| ::peek_from(bytes, e)) + } + })+ + } +} + +impl_for_arrays! { + 01 02 03 04 05 06 07 08 09 10 + 11 12 13 14 15 16 17 18 19 20 + 21 22 23 24 25 26 27 28 29 30 + 31 32 +} + +unsafe impl Poke for () { + fn max_size() -> usize { + 0 + } + unsafe fn poke_into(&self, bytes: *mut u8) -> *mut u8 { + bytes + } +} +impl Peek for () { + unsafe fn peek_from(bytes: *const u8, output: *mut Self) -> *const u8 { + *output = (); + bytes + } +} + +macro_rules! impl_for_tuple { + ($($n:tt: $ty:ident),+) => { + unsafe impl<$($ty: Poke),+> Poke for ($($ty,)+) { + #[inline(always)] + fn max_size() -> usize { + 0 $(+ <$ty>::max_size())+ + } + unsafe fn poke_into(&self, bytes: *mut u8) -> *mut u8 { + $(let bytes = self.$n.poke_into(bytes);)+ + bytes + } + } + impl<$($ty: Peek),+> Peek for ($($ty,)+) { + unsafe fn peek_from(bytes: *const u8, output: *mut Self) -> *const u8 { + $(let bytes = $ty::peek_from(bytes, &mut (*output).$n);)+ + bytes + } + } + } +} + +impl_for_tuple!(0: A); +impl_for_tuple!(0: A, 1: B); +impl_for_tuple!(0: A, 1: B, 2: C); +impl_for_tuple!(0: A, 1: B, 2: C, 3: D); +impl_for_tuple!(0: A, 1: B, 2: C, 3: D, 4: E); diff --git a/gfx/wr/peek-poke/src/slice_ext.rs b/gfx/wr/peek-poke/src/slice_ext.rs new file mode 100644 index 000000000000..f309d2f74102 --- /dev/null +++ b/gfx/wr/peek-poke/src/slice_ext.rs @@ -0,0 +1,19 @@ +// Copyright 2019 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub trait AsEndMutPtr { + fn as_end_mut_ptr(self) -> *mut T; +} + +impl<'a> AsEndMutPtr for &'a mut [u8] { + fn as_end_mut_ptr(self) -> *mut u8 { + unsafe { self.as_mut_ptr().add(self.len()) } + } +} diff --git a/gfx/wr/peek-poke/src/vec_ext.rs b/gfx/wr/peek-poke/src/vec_ext.rs new file mode 100644 index 000000000000..42e26032e52a --- /dev/null +++ b/gfx/wr/peek-poke/src/vec_ext.rs @@ -0,0 +1,26 @@ +// Copyright 2019 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::vec::Vec; + +pub trait VecExt { + type Item; + unsafe fn set_end_ptr(&mut self, end: *const Self::Item); +} + +impl VecExt for Vec { + type Item = T; + unsafe fn set_end_ptr(&mut self, end: *const T) { + assert!(end as usize >= self.as_ptr() as usize); + let new_len = end as usize - self.as_ptr() as usize; + assert!(new_len <= self.capacity()); + self.set_len(new_len); + } +} diff --git a/gfx/wr/peek-poke/tests/max_size.rs b/gfx/wr/peek-poke/tests/max_size.rs new file mode 100644 index 000000000000..5f9f9ca52efc --- /dev/null +++ b/gfx/wr/peek-poke/tests/max_size.rs @@ -0,0 +1,117 @@ +// Copyright 2019 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(dead_code)] + +use peek_poke::{PeekPoke, Poke}; +use std::{marker::PhantomData, mem::size_of}; + +#[test] +fn test_numbers() { + assert_eq!(u8::max_size(), size_of::()); + assert_eq!(u16::max_size(), size_of::()); + assert_eq!(u32::max_size(), size_of::()); + assert_eq!(u64::max_size(), size_of::()); + assert_eq!(usize::max_size(), size_of::()); + assert_eq!(i8::max_size(), size_of::()); + assert_eq!(i16::max_size(), size_of::()); + assert_eq!(i32::max_size(), size_of::()); + assert_eq!(i64::max_size(), size_of::()); + assert_eq!(isize::max_size(), size_of::()); + // floating + assert_eq!(f32::max_size(), size_of::()); + assert_eq!(f64::max_size(), size_of::()); +} + +#[test] +fn test_bool() { + assert_eq!(bool::max_size(), size_of::()); +} + +#[test] +fn test_option() { + assert_eq!( + Option::::max_size(), + ::max_size() + ::max_size() + ); +} + +#[test] +fn test_fixed_size_array() { + assert_eq!(<[u32; 32]>::max_size(), 32 * size_of::()); + assert_eq!(<[u64; 8]>::max_size(), 8 * size_of::()); + assert_eq!(<[u8; 19]>::max_size(), 19 * size_of::()); +} + +#[test] +fn test_tuple() { + assert_eq!(<(isize)>::max_size(), size_of::()); + assert_eq!(<(isize, isize, isize)>::max_size(), 3 * size_of::()); + assert_eq!(<(isize, ())>::max_size(), size_of::()); +} + +#[test] +fn test_basic_struct() { + #[derive(Debug, PeekPoke)] + struct Bar { + a: u32, + b: u32, + c: u32, + } + + assert_eq!(::max_size(), 3 * ::max_size()); +} + +#[test] +fn test_enum() { + #[derive(Clone, Copy, PeekPoke)] + enum TestEnum { + NoArg, + OneArg(usize), + Args(usize, usize), + AnotherNoArg, + StructLike { x: usize, y: f32 }, + } + assert_eq!( + TestEnum::max_size(), + ::max_size() + 2 * ::max_size() + ); +} + +#[test] +fn test_enum_cstyle() { + #[repr(u32)] + #[derive(Clone, Copy, PeekPoke)] + enum BorderStyle { + None = 0, + Solid = 1, + Double = 2, + Dotted = 3, + Dashed = 4, + Hidden = 5, + Groove = 6, + Ridge = 7, + Inset = 8, + Outset = 9, + } + assert_eq!(BorderStyle::max_size(), ::max_size()); +} + +#[test] +fn test_phantom_data() { + struct Bar; + #[derive(PeekPoke)] + struct Foo { + x: u32, + y: u32, + _marker: PhantomData, + } + assert_eq!(Foo::max_size(), 2 * size_of::()) +} diff --git a/gfx/wr/peek-poke/tests/round_trip.rs b/gfx/wr/peek-poke/tests/round_trip.rs new file mode 100644 index 000000000000..3134c207ec4d --- /dev/null +++ b/gfx/wr/peek-poke/tests/round_trip.rs @@ -0,0 +1,275 @@ +// Copyright 2019 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use peek_poke::{Peek, PeekPoke, Poke}; +use std::{fmt::Debug, marker::PhantomData}; + +fn poke_into(a: &V) -> Vec { + let mut v = >::with_capacity(::max_size()); + let end_ptr = unsafe { a.poke_into(v.as_mut_ptr()) }; + let new_size = end_ptr as usize - v.as_ptr() as usize; + assert!(new_size <= v.capacity()); + unsafe { + v.set_len(new_size); + } + v +} + +#[cfg(not(feature = "option_copy"))] +fn the_same(a: V) +where + V: Debug + Default + PartialEq + Peek + Poke, +{ + let v = poke_into(&a); + let (b, end_ptr) = unsafe { peek_poke::peek_from_default(v.as_ptr()) }; + let size = end_ptr as usize - v.as_ptr() as usize; + assert_eq!(size, v.len()); + assert_eq!(a, b); +} + +#[cfg(feature = "option_copy")] +fn the_same(a: V) +where + V: Copy + Debug + PartialEq + Peek + Poke, +{ + let v = poke_into(&a); + let mut b = a; + let end_ptr = unsafe { b.peek_from(v.as_ptr()) }; + let size = end_ptr as usize - v.as_ptr() as usize; + assert_eq!(size, v.len()); + assert_eq!(a, b); +} + +#[test] +fn test_numbers() { + // unsigned positive + the_same(5u8); + the_same(5u16); + the_same(5u32); + the_same(5u64); + the_same(5usize); + // signed positive + the_same(5i8); + the_same(5i16); + the_same(5i32); + the_same(5i64); + the_same(5isize); + // signed negative + the_same(-5i8); + the_same(-5i16); + the_same(-5i32); + the_same(-5i64); + the_same(-5isize); + // floating + the_same(-100f32); + the_same(0f32); + the_same(5f32); + the_same(-100f64); + the_same(5f64); +} + +#[test] +fn test_bool() { + the_same(true); + the_same(false); +} + +#[cfg(any(feature = "option_copy", feature = "option_default"))] +#[test] +fn test_option() { + the_same(Some(5usize)); + //the_same(Some("foo bar".to_string())); + the_same(None::); +} + +#[test] +fn test_fixed_size_array() { + the_same([24u32; 32]); + the_same([1u64, 2, 3, 4, 5, 6, 7, 8]); + the_same([0u8; 19]); +} + +#[test] +fn test_tuple() { + the_same((1isize, )); + the_same((1isize, 2isize, 3isize)); + the_same((1isize, ())); +} + +#[test] +fn test_basic_struct() { + #[derive(Copy, Clone, Debug, Default, PartialEq, PeekPoke)] + struct Bar { + a: u32, + b: u32, + c: u32, + #[cfg(any(feature = "option_copy", feature = "option_default"))] + d: Option, + } + + the_same(Bar { + a: 2, + b: 4, + c: 42, + #[cfg(any(feature = "option_copy", feature = "option_default"))] + d: None, + }); +} + +#[test] +fn test_enum() { + #[derive(Clone, Copy, Debug, PartialEq, PeekPoke)] + enum TestEnum { + NoArg, + OneArg(usize), + Args(usize, usize), + AnotherNoArg, + StructLike { x: usize, y: f32 }, + } + + impl Default for TestEnum { + fn default() -> Self { + TestEnum::NoArg + } + } + + the_same(TestEnum::NoArg); + the_same(TestEnum::OneArg(4)); + the_same(TestEnum::Args(4, 5)); + the_same(TestEnum::AnotherNoArg); + the_same(TestEnum::StructLike { x: 4, y: 3.14159 }); +} + +#[test] +fn test_enum_cstyle() { + #[repr(u32)] + #[derive(Clone, Copy, Debug, PartialEq, Eq, PeekPoke)] + enum BorderStyle { + None = 0, + Solid = 1, + Double = 2, + Dotted = 3, + Dashed = 4, + Hidden = 5, + Groove = 6, + Ridge = 7, + Inset = 8, + Outset = 9, + } + + impl Default for BorderStyle { + fn default() -> Self { + BorderStyle::None + } + } + + the_same(BorderStyle::None); + the_same(BorderStyle::Solid); + the_same(BorderStyle::Double); + the_same(BorderStyle::Dotted); + the_same(BorderStyle::Dashed); + the_same(BorderStyle::Hidden); + the_same(BorderStyle::Groove); + the_same(BorderStyle::Ridge); + the_same(BorderStyle::Inset); + the_same(BorderStyle::Outset); +} + +#[test] +fn test_phantom_data() { + struct Bar; + #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PeekPoke)] + struct Foo { + x: u32, + y: u32, + _marker: PhantomData, + } + the_same(Foo { + x: 19, + y: 42, + _marker: PhantomData, + }); +} + +#[test] +fn test_generic() { + #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PeekPoke)] + struct Foo { + x: T, + y: T, + } + the_same(Foo { x: 19.0, y: 42.0 }); +} + +#[test] +fn test_generic_enum() { + #[derive(Clone, Copy, Debug, Default, PartialEq, PeekPoke)] + pub struct PropertyBindingKey { + pub id: usize, + _phantom: PhantomData, + } + + #[derive(Clone, Copy, Debug, PartialEq, PeekPoke)] + pub enum PropertyBinding { + Value(T), + Binding(PropertyBindingKey, T), + } + + impl Default for PropertyBinding { + fn default() -> Self { + PropertyBinding::Value(Default::default()) + } + } +} + +#[cfg(all(feature = "extras", feature = "option_copy"))] +mod extra_tests { + use super::*; + use euclid::{Point2D, Rect, SideOffsets2D, Size2D, Transform3D, Vector2D}; + use std::mem::size_of; + + #[test] + fn euclid_types() { + the_same(Point2D::::new(1.0, 2.0)); + assert_eq!(Point2D::::max_size(), 2 * size_of::()); + + the_same(Rect::::new( + Point2D::::new(0.0, 0.0), + Size2D::::new(100.0, 80.0), + )); + assert_eq!(Rect::::max_size(), 4 * size_of::()); + + the_same(SideOffsets2D::::new(0.0, 10.0, -1.0, -10.0)); + assert_eq!(SideOffsets2D::::max_size(), 4 * size_of::()); + + the_same(Transform3D::::identity()); + assert_eq!(Transform3D::::max_size(), 16 * size_of::()); + + the_same(Vector2D::::new(1.0, 2.0)); + assert_eq!(Vector2D::::max_size(), 2 * size_of::()); + } + + #[test] + fn webrender_api_types() { + type PipelineSourceId = i32; + #[derive(Clone, Copy, Debug, PartialEq, PeekPoke)] + struct PipelineId(pub PipelineSourceId, pub u32); + + #[derive(Clone, Copy, Debug, PartialEq, PeekPoke)] + struct ClipChainId(pub u64, pub PipelineId); + + #[derive(Clone, Copy, Debug, PartialEq, PeekPoke)] + struct SpatialId(pub usize, pub PipelineId); + + the_same(PipelineId(42, 2)); + the_same(ClipChainId(19u64, PipelineId(42, 2))); + the_same(SpatialId(19usize, PipelineId(42, 2))); + } +} diff --git a/gfx/wr/webrender/src/resource_cache.rs b/gfx/wr/webrender/src/resource_cache.rs index 25ab8cad748c..965119ae4001 100644 --- a/gfx/wr/webrender/src/resource_cache.rs +++ b/gfx/wr/webrender/src/resource_cache.rs @@ -894,7 +894,13 @@ impl ResourceCache { ) * tile_size as i32; rect.origin -= tile_offset.to_vector(); - rect + let tile_rect = compute_tile_size( + &descriptor.size.into(), + tile_size, + tile, + ).into(); + + rect.intersection(&tile_rect).unwrap_or(DeviceIntRect::zero()) }) } (None, Some(..)) => DirtyRect::All, diff --git a/gfx/wr/webrender_api/Cargo.toml b/gfx/wr/webrender_api/Cargo.toml index 585a3a812c8d..f86a6fb89ad7 100644 --- a/gfx/wr/webrender_api/Cargo.toml +++ b/gfx/wr/webrender_api/Cargo.toml @@ -16,18 +16,18 @@ display_list_stats = [] [dependencies] app_units = "0.7" -bincode = "1.0" bitflags = "1.0" byteorder = "1.2.1" derive_more = "0.13" ipc-channel = {version = "0.11.0", optional = true} -euclid = { version = "0.19.5", features = ["serde"] } +euclid = { version = "0.19.9", features = ["serde"] } malloc_size_of_derive = "0.1" serde = { version = "=1.0.88", features = ["rc"] } -serde_derive = { version = "=1.0.88", features = ["deserialize_in_place"] } +serde_derive = "=1.0.88" serde_bytes = "0.10" time = "0.1" malloc_size_of = { version = "0.0.1", path = "../wr_malloc_size_of", package = "wr_malloc_size_of" } +peek-poke = { version = "0.2", path = "../peek-poke", features = ["extras"] } [target.'cfg(target_os = "macos")'.dependencies] core-foundation = "0.6" diff --git a/gfx/wr/webrender_api/src/api.rs b/gfx/wr/webrender_api/src/api.rs index 335e9cb16d78..fb97036e4d04 100644 --- a/gfx/wr/webrender_api/src/api.rs +++ b/gfx/wr/webrender_api/src/api.rs @@ -5,6 +5,7 @@ extern crate serde_bytes; use crate::channel::{self, MsgSender, Payload, PayloadSender, PayloadSenderHelperMethods}; +use peek_poke::PeekPoke; use std::cell::Cell; use std::fmt; use std::marker::PhantomData; @@ -795,11 +796,12 @@ impl Epoch { } #[repr(C)] -#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, Hash, Ord, PartialOrd, Deserialize, Serialize)] +#[derive(Clone, Copy, Debug, Default, Eq, MallocSizeOf, PartialEq, Hash, Ord, PartialOrd, PeekPoke)] +#[derive(Deserialize, Serialize)] pub struct IdNamespace(pub u32); #[repr(C)] -#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)] pub struct DocumentId { pub namespace_id: IdNamespace, pub id: u32, @@ -825,9 +827,15 @@ pub type PipelineSourceId = u32; /// From the point of view of WR, `PipelineId` is completely opaque and generic as long as /// it's clonable, serializable, comparable, and hashable. #[repr(C)] -#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)] pub struct PipelineId(pub PipelineSourceId, pub u32); +impl Default for PipelineId { + fn default() -> Self { + PipelineId::dummy() + } +} + impl PipelineId { pub fn dummy() -> Self { PipelineId(0, 0) @@ -1416,7 +1424,7 @@ impl ZoomFactor { } #[repr(C)] -#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize, Eq, Hash)] +#[derive(Clone, Copy, Debug, Default, Deserialize, MallocSizeOf, PartialEq, Serialize, Eq, Hash, PeekPoke)] pub struct PropertyBindingId { namespace: IdNamespace, uid: u32, @@ -1434,7 +1442,7 @@ impl PropertyBindingId { /// A unique key that is used for connecting animated property /// values to bindings in the display list. #[repr(C)] -#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] pub struct PropertyBindingKey { pub id: PropertyBindingId, _phantom: PhantomData, @@ -1463,12 +1471,18 @@ impl PropertyBindingKey { /// used for the case where the animation is still in-delay phase /// (i.e. the animation doesn't produce any animation values). #[repr(C)] -#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, PeekPoke)] pub enum PropertyBinding { Value(T), Binding(PropertyBindingKey, T), } +impl Default for PropertyBinding { + fn default() -> Self { + PropertyBinding::Value(Default::default()) + } +} + impl From for PropertyBinding { fn from(value: T) -> PropertyBinding { PropertyBinding::Value(value) diff --git a/gfx/wr/webrender_api/src/color.rs b/gfx/wr/webrender_api/src/color.rs index 1861a9ac5f0b..b609548c32cf 100644 --- a/gfx/wr/webrender_api/src/color.rs +++ b/gfx/wr/webrender_api/src/color.rs @@ -2,6 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +use peek_poke::PeekPoke; use std::cmp; use std::hash::{Hash, Hasher}; @@ -37,7 +38,7 @@ impl PremultipliedColorF { /// All components must be between 0.0 and 1.0. /// An alpha value of 1.0 is opaque while 0.0 is fully transparent. #[repr(C)] -#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Default, Deserialize, MallocSizeOf, PartialEq, Serialize, PeekPoke)] pub struct ColorF { pub r: f32, pub g: f32, diff --git a/gfx/wr/webrender_api/src/display_item.rs b/gfx/wr/webrender_api/src/display_item.rs index 8c820c152bf2..af3c20be1abe 100644 --- a/gfx/wr/webrender_api/src/display_item.rs +++ b/gfx/wr/webrender_api/src/display_item.rs @@ -3,6 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use euclid::SideOffsets2D; +use peek_poke::PeekPoke; use std::ops::Not; // local imports use crate::font; @@ -34,7 +35,7 @@ pub type ItemTag = (u64, u16); /// A grouping of fields a lot of display items need, just to avoid /// repeating these over and over in this file. -#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] pub struct CommonItemProperties { /// Bounds of the display item to clip to. Many items are logically /// infinite, and rely on this clip_rect to define their bounds @@ -71,7 +72,7 @@ impl CommonItemProperties { /// Note: this is a separate struct from `PrimitiveInfo` because /// it needs indirectional mapping during the DL flattening phase, /// turning into `ScrollNodeAndClipChain`. -#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] pub struct SpaceAndClipInfo { pub spatial_id: SpatialId, pub clip_id: ClipId, @@ -89,7 +90,7 @@ impl SpaceAndClipInfo { } #[repr(u8)] -#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, PeekPoke)] pub enum DisplayItem { // These are the "real content" display items Rectangle(RectangleDisplayItem), @@ -167,7 +168,7 @@ pub enum DebugDisplayItem { PopAllShadows, } -#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] pub struct ClipDisplayItem { pub id: ClipId, pub parent_space_and_clip: SpaceAndClipInfo, @@ -177,7 +178,7 @@ pub struct ClipDisplayItem { /// The minimum and maximum allowable offset for a sticky frame in a single dimension. #[repr(C)] -#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] pub struct StickyOffsetBounds { /// The minimum offset for this frame, typically a negative value, which specifies how /// far in the negative direction the sticky frame can offset its contents in this @@ -196,7 +197,7 @@ impl StickyOffsetBounds { } } -#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] pub struct StickyFrameDisplayItem { pub id: SpatialId, pub parent_spatial_id: SpatialId, @@ -227,13 +228,13 @@ pub struct StickyFrameDisplayItem { pub previously_applied_offset: LayoutVector2D, } -#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, PeekPoke)] pub enum ScrollSensitivity { ScriptAndInputEvents, Script, } -#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] pub struct ScrollFrameDisplayItem { /// The id of the clip this scroll frame creates pub clip_id: ClipId, @@ -256,7 +257,7 @@ pub struct ScrollFrameDisplayItem { } /// A solid color to draw (may not actually be a rectangle due to complex clips) -#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] pub struct RectangleDisplayItem { pub common: CommonItemProperties, pub color: ColorF, @@ -264,7 +265,7 @@ pub struct RectangleDisplayItem { /// Clears all colors from the area, making it possible to cut holes in the window. /// (useful for things like the macos frosted-glass effect). -#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] pub struct ClearRectangleDisplayItem { pub common: CommonItemProperties, } @@ -272,12 +273,12 @@ pub struct ClearRectangleDisplayItem { /// A minimal hit-testable item for the parent browser's convenience, and is /// slimmer than a RectangleDisplayItem (no color). The existence of this as a /// distinct item also makes it easier to inspect/debug display items. -#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] pub struct HitTestDisplayItem { pub common: CommonItemProperties, } -#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] pub struct LineDisplayItem { pub common: CommonItemProperties, /// We need a separate rect from common.clip_rect to encode cute @@ -299,14 +300,14 @@ pub struct LineDisplayItem { } #[repr(u8)] -#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize, Eq, Hash)] +#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize, Eq, Hash, PeekPoke)] pub enum LineOrientation { Vertical, Horizontal, } #[repr(u8)] -#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize, Eq, Hash)] +#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize, Eq, Hash, PeekPoke)] pub enum LineStyle { Solid, Dotted, @@ -314,7 +315,7 @@ pub enum LineStyle { Wavy, } -#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] pub struct TextDisplayItem { pub common: CommonItemProperties, /// The area all the glyphs should be found in. Strictly speaking this isn't @@ -330,7 +331,7 @@ pub struct TextDisplayItem { pub glyph_options: Option, } // IMPLICIT: glyphs: Vec -#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Default, Deserialize, MallocSizeOf, PartialEq, Serialize, PeekPoke)] pub struct NormalBorder { pub left: BorderSide, pub right: BorderSide, @@ -389,7 +390,7 @@ impl NormalBorder { } #[repr(u8)] -#[derive(Debug, Copy, Clone, MallocSizeOf, PartialEq, Serialize, Deserialize, Eq, Hash)] +#[derive(Debug, Copy, Clone, MallocSizeOf, PartialEq, Serialize, Deserialize, Eq, Hash, PeekPoke)] pub enum RepeatMode { Stretch, Repeat, @@ -397,14 +398,14 @@ pub enum RepeatMode { Space, } -#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, PeekPoke)] pub enum NinePatchBorderSource { Image(ImageKey), Gradient(Gradient), RadialGradient(RadialGradient), } -#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] pub struct NinePatchBorder { /// Describes what to use as the 9-patch source image. If this is an image, /// it will be stretched to fill the size given by width x height. @@ -442,13 +443,13 @@ pub struct NinePatchBorder { pub outset: SideOffsets2D, } -#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, PeekPoke)] pub enum BorderDetails { Normal(NormalBorder), NinePatch(NinePatchBorder), } -#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] pub struct BorderDisplayItem { pub common: CommonItemProperties, pub bounds: LayoutRect, @@ -457,14 +458,14 @@ pub struct BorderDisplayItem { } #[repr(C)] -#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, PeekPoke)] pub enum BorderRadiusKind { Uniform, NonUniform, } #[repr(C)] -#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize, PeekPoke)] pub struct BorderRadius { pub top_left: LayoutSize, pub top_right: LayoutSize, @@ -472,15 +473,26 @@ pub struct BorderRadius { pub bottom_right: LayoutSize, } +impl Default for BorderRadius { + fn default() -> Self { + BorderRadius { + top_left: LayoutSize::zero(), + top_right: LayoutSize::zero(), + bottom_left: LayoutSize::zero(), + bottom_right: LayoutSize::zero(), + } + } +} + #[repr(C)] -#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Default, Deserialize, MallocSizeOf, PartialEq, Serialize, PeekPoke)] pub struct BorderSide { pub color: ColorF, pub style: BorderStyle, } #[repr(u32)] -#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize, Hash, Eq)] +#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize, Hash, Eq, PeekPoke)] pub enum BorderStyle { None = 0, Solid = 1, @@ -501,13 +513,13 @@ impl BorderStyle { } #[repr(u8)] -#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)] pub enum BoxShadowClipMode { Outset = 0, Inset = 1, } -#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] pub struct BoxShadowDisplayItem { pub common: CommonItemProperties, pub box_bounds: LayoutRect, @@ -519,7 +531,7 @@ pub struct BoxShadowDisplayItem { pub clip_mode: BoxShadowClipMode, } -#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] pub struct PushShadowDisplayItem { pub space_and_clip: SpaceAndClipInfo, pub shadow: Shadow, @@ -527,7 +539,7 @@ pub struct PushShadowDisplayItem { } #[repr(C)] -#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] pub struct Shadow { pub offset: LayoutVector2D, pub color: ColorF, @@ -535,13 +547,13 @@ pub struct Shadow { } #[repr(u8)] -#[derive(Debug, Copy, Clone, Hash, Eq, MallocSizeOf, PartialEq, Serialize, Deserialize, Ord, PartialOrd)] +#[derive(Debug, Copy, Clone, Hash, Eq, MallocSizeOf, PartialEq, Serialize, Deserialize, Ord, PartialOrd, PeekPoke)] pub enum ExtendMode { Clamp, Repeat, } -#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] pub struct Gradient { pub start_point: LayoutPoint, pub end_point: LayoutPoint, @@ -549,7 +561,7 @@ pub struct Gradient { } // IMPLICIT: stops: Vec /// The area -#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] pub struct GradientDisplayItem { /// NOTE: common.clip_rect is the area the gradient covers pub common: CommonItemProperties, @@ -565,13 +577,13 @@ pub struct GradientDisplayItem { } #[repr(C)] -#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Default, Deserialize, MallocSizeOf, PartialEq, Serialize, PeekPoke)] pub struct GradientStop { pub offset: f32, pub color: ColorF, } -#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] pub struct RadialGradient { pub center: LayoutPoint, pub radius: LayoutSize, @@ -581,13 +593,13 @@ pub struct RadialGradient { } // IMPLICIT stops: Vec /// Just an abstraction for bundling up a bunch of clips into a "super clip". -#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] pub struct ClipChainItem { pub id: ClipChainId, pub parent: Option, } // IMPLICIT clip_ids: Vec -#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] pub struct RadialGradientDisplayItem { pub common: CommonItemProperties, /// The area to tile the gradient over (first tile starts at origin of this rect) @@ -599,14 +611,14 @@ pub struct RadialGradientDisplayItem { pub tile_spacing: LayoutSize, } -#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] pub struct ReferenceFrameDisplayListItem { pub origin: LayoutPoint, pub parent_spatial_id: SpatialId, pub reference_frame: ReferenceFrame, } -#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, PeekPoke)] pub enum ReferenceFrameKind { Transform, Perspective { @@ -614,7 +626,7 @@ pub enum ReferenceFrameKind { } } -#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] pub struct ReferenceFrame { pub kind: ReferenceFrameKind, pub transform_style: TransformStyle, @@ -624,7 +636,7 @@ pub struct ReferenceFrame { pub id: SpatialId, } -#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] pub struct PushStackingContextDisplayItem { pub origin: LayoutPoint, pub spatial_id: SpatialId, @@ -632,7 +644,7 @@ pub struct PushStackingContextDisplayItem { pub stacking_context: StackingContext, } -#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] pub struct StackingContext { pub transform_style: TransformStyle, pub mix_blend_mode: MixBlendMode, @@ -643,7 +655,7 @@ pub struct StackingContext { } // IMPLICIT: filters: Vec, filter_datas: Vec, filter_primitives: Vec #[repr(u8)] -#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize, PeekPoke)] pub enum TransformStyle { Flat = 0, Preserve3D = 1, @@ -655,7 +667,7 @@ pub enum TransformStyle { /// when we want to cache the output, and performance is /// important. Note that this is a performance hint only, /// which WR may choose to ignore. -#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, PeekPoke)] #[repr(u8)] pub enum RasterSpace { // Rasterize in local-space, applying supplied scale to primitives. @@ -679,7 +691,7 @@ impl RasterSpace { } #[repr(u8)] -#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)] pub enum MixBlendMode { Normal = 0, Multiply = 1, @@ -701,14 +713,14 @@ pub enum MixBlendMode { /// An input to a SVG filter primitive. #[repr(C)] -#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)] pub enum ColorSpace { Srgb, LinearRgb, } #[repr(C)] -#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)] pub enum FilterPrimitiveInput { /// The input is the original graphic that the filter is being applied to. Original, @@ -731,7 +743,7 @@ impl FilterPrimitiveInput { } #[repr(C)] -#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] pub struct BlendPrimitive { pub input1: FilterPrimitiveInput, pub input2: FilterPrimitiveInput, @@ -739,7 +751,7 @@ pub struct BlendPrimitive { } #[repr(C)] -#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] pub struct FloodPrimitive { pub color: ColorF, } @@ -754,7 +766,7 @@ impl FloodPrimitive { } #[repr(C)] -#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] pub struct BlurPrimitive { pub input: FilterPrimitiveInput, pub radius: f32, @@ -767,7 +779,7 @@ impl BlurPrimitive { } #[repr(C)] -#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] pub struct OpacityPrimitive { pub input: FilterPrimitiveInput, pub opacity: f32, @@ -781,14 +793,14 @@ impl OpacityPrimitive { /// cbindgen:derive-eq=false #[repr(C)] -#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] pub struct ColorMatrixPrimitive { pub input: FilterPrimitiveInput, pub matrix: [f32; 20], } #[repr(C)] -#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] pub struct DropShadowPrimitive { pub input: FilterPrimitiveInput, pub shadow: Shadow, @@ -801,14 +813,14 @@ impl DropShadowPrimitive { } #[repr(C)] -#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] pub struct ComponentTransferPrimitive { pub input: FilterPrimitiveInput, // Component transfer data is stored in FilterData. } #[repr(C)] -#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] pub struct IdentityPrimitive { pub input: FilterPrimitiveInput, } @@ -816,7 +828,7 @@ pub struct IdentityPrimitive { /// See: https://github.com/eqrion/cbindgen/issues/9 /// cbindgen:derive-eq=false #[repr(C)] -#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, PeekPoke)] pub enum FilterPrimitiveKind { Identity(IdentityPrimitive), Blend(BlendPrimitive), @@ -830,6 +842,12 @@ pub enum FilterPrimitiveKind { ComponentTransfer(ComponentTransferPrimitive), } +impl Default for FilterPrimitiveKind { + fn default() -> Self { + FilterPrimitiveKind::Identity(IdentityPrimitive::default()) + } +} + impl FilterPrimitiveKind { pub fn sanitize(&mut self) { match self { @@ -852,7 +870,7 @@ impl FilterPrimitiveKind { /// See: https://github.com/eqrion/cbindgen/issues/9 /// cbindgen:derive-eq=false #[repr(C)] -#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] pub struct FilterPrimitive { pub kind: FilterPrimitiveKind, pub color_space: ColorSpace, @@ -866,7 +884,7 @@ impl FilterPrimitive { /// CSS filter. #[repr(C)] -#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] +#[derive(Clone, Copy, Debug, PartialEq, Deserialize, Serialize, PeekPoke)] pub enum FilterOp { /// Filter that does no transformation of the colors, needed for /// debug purposes only. @@ -889,7 +907,7 @@ pub enum FilterOp { } #[repr(u8)] -#[derive(Clone, Copy, Debug, PartialEq, Deserialize, Serialize)] +#[derive(Clone, Copy, Debug, PartialEq, Deserialize, Serialize, PeekPoke)] pub enum ComponentTransferFuncType { Identity = 0, Table = 1, @@ -985,7 +1003,7 @@ impl FilterData { } } -#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] pub struct IframeDisplayItem { pub bounds: LayoutRect, pub clip_rect: LayoutRect, @@ -996,7 +1014,7 @@ pub struct IframeDisplayItem { /// This describes an image or, more generally, a background-image and its tiling. /// (A background-image repeats in a grid to fill the specified area). -#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] pub struct ImageDisplayItem { pub common: CommonItemProperties, /// The area to tile the image over (first tile starts at origin of this rect) @@ -1015,20 +1033,20 @@ pub struct ImageDisplayItem { } #[repr(u8)] -#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)] pub enum ImageRendering { Auto = 0, CrispEdges = 1, Pixelated = 2, } -#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)] pub enum AlphaType { Alpha = 0, PremultipliedAlpha = 1, } -#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] pub struct YuvImageDisplayItem { pub common: CommonItemProperties, pub bounds: LayoutRect, @@ -1039,14 +1057,14 @@ pub struct YuvImageDisplayItem { } #[repr(u8)] -#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)] pub enum YuvColorSpace { Rec601 = 0, Rec709 = 1, Rec2020 = 2, } -#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize, PeekPoke)] pub enum YuvData { NV12(ImageKey, ImageKey), // (Y channel, CbCr interleaved channel) PlanarYCbCr(ImageKey, ImageKey, ImageKey), // (Y channel, Cb channel, Cr Channel) @@ -1063,7 +1081,7 @@ impl YuvData { } } -#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)] pub enum YuvFormat { NV12 = 0, PlanarYCbCr = 1, @@ -1081,7 +1099,7 @@ impl YuvFormat { } #[repr(C)] -#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] pub struct ImageMask { pub image: ImageKey, pub rect: LayoutRect, @@ -1100,7 +1118,7 @@ impl ImageMask { } #[repr(C)] -#[derive(Copy, Clone, Debug, MallocSizeOf, PartialEq, Serialize, Deserialize, Eq, Hash)] +#[derive(Copy, Clone, Debug, MallocSizeOf, PartialEq, Serialize, Deserialize, Eq, Hash, PeekPoke)] pub enum ClipMode { Clip, // Pixels inside the region are visible. ClipOut, // Pixels outside the region are visible. @@ -1118,7 +1136,7 @@ impl Not for ClipMode { } #[repr(C)] -#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] pub struct ComplexClipRegion { /// The boundaries of the rectangle. pub rect: LayoutRect, @@ -1209,11 +1227,11 @@ impl ComplexClipRegion { } } -#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Default, Deserialize, Eq, Hash, PartialEq, Serialize, PeekPoke)] pub struct ClipChainId(pub u64, pub PipelineId); /// A reference to a clipping node defining how an item is clipped. -#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize, PeekPoke)] pub enum ClipId { Clip(usize, PipelineId), ClipChain(ClipChainId), @@ -1256,7 +1274,7 @@ impl ClipId { } /// A reference to a spatial node defining item positioning. -#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Default, Deserialize, Eq, Hash, PartialEq, Serialize, PeekPoke)] pub struct SpatialId(pub usize, PipelineId); const ROOT_REFERENCE_FRAME_SPATIAL_ID: usize = 0; @@ -1295,7 +1313,7 @@ impl SpatialId { /// /// When setting display lists with the `preserve_frame_state` this id is used to preserve scroll /// offsets between different sets of ClipScrollNodes which are ScrollFrames. -#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Default, Deserialize, Eq, Hash, PartialEq, Serialize, PeekPoke)] #[repr(C)] pub struct ExternalScrollId(pub u64, pub PipelineId); @@ -1341,3 +1359,44 @@ impl DisplayItem { } } } + +macro_rules! impl_default_for_enums { + ($($enum:ident => $init:expr ),+) => { + $(impl Default for $enum { + #[allow(unused_imports)] + fn default() -> Self { + use $enum::*; + $init + } + })* + } +} + +impl_default_for_enums! { + DisplayItem => PopStackingContext, + ScrollSensitivity => ScriptAndInputEvents, + LineOrientation => Vertical, + LineStyle => Solid, + RepeatMode => Stretch, + NinePatchBorderSource => Image(ImageKey::default()), + BorderDetails => Normal(NormalBorder::default()), + BorderRadiusKind => Uniform, + BorderStyle => None, + BoxShadowClipMode => Outset, + ExtendMode => Clamp, + FilterOp => Identity, + ComponentTransferFuncType => Identity, + ClipMode => Clip, + ClipId => ClipId::invalid(), + ReferenceFrameKind => Transform, + TransformStyle => Flat, + RasterSpace => Local(f32::default()), + MixBlendMode => Normal, + ImageRendering => Auto, + AlphaType => Alpha, + YuvColorSpace => Rec601, + YuvData => NV12(ImageKey::default(), ImageKey::default()), + YuvFormat => NV12, + FilterPrimitiveInput => Original, + ColorSpace => Srgb +} diff --git a/gfx/wr/webrender_api/src/display_list.rs b/gfx/wr/webrender_api/src/display_list.rs index bf3587eb2495..faaa5e1adc57 100644 --- a/gfx/wr/webrender_api/src/display_list.rs +++ b/gfx/wr/webrender_api/src/display_list.rs @@ -2,17 +2,18 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use bincode; use euclid::SideOffsets2D; +use peek_poke::{ensure_red_zone, peek_from_slice, poke_extend_vec}; +use peek_poke::{poke_inplace_slice, poke_into_vec, Poke}; #[cfg(feature = "deserialize")] use serde::de::Deserializer; #[cfg(feature = "serialize")] use serde::ser::{Serializer, SerializeSeq}; use serde::{Deserialize, Serialize}; -use std::io::{Read, stdout, Write}; +use std::io::{stdout, Write}; use std::marker::PhantomData; use std::ops::Range; -use std::{io, mem, ptr, slice}; +use std::mem; use std::collections::HashMap; use time::precise_time_ns; // local imports @@ -67,18 +68,15 @@ impl<'a, T> ItemRange<'a, T> { } } -impl<'a, T> ItemRange<'a, T> -where - for<'de> T: Deserialize<'de>, -{ +impl<'a, T: Default> ItemRange<'a, T> { pub fn iter(&self) -> AuxIter<'a, T> { - AuxIter::new(self.bytes) + AuxIter::new(T::default(), self.bytes) } } impl<'a, T> IntoIterator for ItemRange<'a, T> where - for<'de> T: Deserialize<'de>, + T: Copy + Default + peek_poke::Peek, { type Item = T; type IntoIter = AuxIter<'a, T>; @@ -176,7 +174,7 @@ impl DebugStats { /// Logs the stats for the given serialized slice #[cfg(feature = "display_list_stats")] - fn log_slice Deserialize<'de>>( + fn log_slice( &mut self, slice_name: &'static str, range: &ItemRange, @@ -186,7 +184,7 @@ impl DebugStats { // processed, and the `range` has everything we need. self.last_addr = range.bytes.as_ptr() as usize + range.bytes.len(); - self._update_entry(slice_name, range.iter().size_hint().0, range.bytes.len()); + self._update_entry(slice_name, range.iter().len(), range.bytes.len()); } #[cfg(not(feature = "display_list_stats"))] @@ -217,9 +215,10 @@ enum Peek { #[derive(Clone)] pub struct AuxIter<'a, T> { + item: T, data: &'a [u8], size: usize, - _boo: PhantomData, +// _boo: PhantomData, } impl BuiltDisplayListDescriptor {} @@ -268,11 +267,10 @@ impl BuiltDisplayList { } } -/// Returns the byte-range the slice occupied, and the number of elements -/// in the slice. -fn skip_slice<'a, T: for<'de> Deserialize<'de>>(mut data: &mut &'a [u8]) -> ItemRange<'a, T> { - let skip_offset: usize = bincode::deserialize_from(&mut data).expect("MEH: malicious input?"); - +/// Returns the byte-range the slice occupied. +fn skip_slice<'a, T: peek_poke::Peek>(data: &mut &'a [u8]) -> ItemRange<'a, T> { + let mut skip_offset = 0usize; + *data = peek_from_slice(data, &mut skip_offset); let (skip, rest) = data.split_at(skip_offset); // Adjust data pointer to skip read values @@ -357,16 +355,14 @@ impl<'a> BuiltDisplayListIter<'a> { pub fn next_raw<'b>(&'b mut self) -> Option> { use crate::DisplayItem::*; - if self.data.is_empty() { + // A "red zone" of DisplayItem::max_size() bytes has been added to the + // end of the serialized display list. If this amount, or less, is + // remaining then we've reached the end of the display list. + if self.data.len() <= di::DisplayItem::max_size() { return None; } - { - let reader = bincode::IoReader::new(UnsafeReader::new(&mut self.data)); - bincode::deserialize_in_place(reader, &mut self.cur_item) - .expect("MEH: malicious process?"); - } - + self.data = peek_from_slice(self.data, &mut self.cur_item); self.log_item_stats(); match self.cur_item { @@ -527,34 +523,32 @@ impl<'a, 'b> DisplayItemRef<'a, 'b> { } } -impl<'de, 'a, T: Deserialize<'de>> AuxIter<'a, T> { - pub fn new(mut data: &'a [u8]) -> Self { - let size: usize = if data.is_empty() { - 0 // Accept empty ItemRanges pointing anywhere - } else { - bincode::deserialize_from(&mut UnsafeReader::new(&mut data)).expect("MEH: malicious input?") +impl<'a, T> AuxIter<'a, T> { + pub fn new(item: T, mut data: &'a [u8]) -> Self { + let mut size = 0usize; + if !data.is_empty() { + data = peek_from_slice(data, &mut size); }; AuxIter { + item, data, size, - _boo: PhantomData, +// _boo: PhantomData, } } } -impl<'a, T: for<'de> Deserialize<'de>> Iterator for AuxIter<'a, T> { +impl<'a, T: Copy + peek_poke::Peek> Iterator for AuxIter<'a, T> { type Item = T; - fn next(&mut self) -> Option { + fn next(&mut self) -> Option { if self.size == 0 { None } else { self.size -= 1; - Some( - bincode::deserialize_from(&mut UnsafeReader::new(&mut self.data)) - .expect("MEH: malicious input?"), - ) + self.data = peek_from_slice(self.data, &mut self.item); + Some(self.item) } } @@ -563,7 +557,7 @@ impl<'a, T: for<'de> Deserialize<'de>> Iterator for AuxIter<'a, T> { } } -impl<'a, T: for<'de> Deserialize<'de>> ::std::iter::ExactSizeIterator for AuxIter<'a, T> {} +impl<'a, T: Copy + peek_poke::Peek> ::std::iter::ExactSizeIterator for AuxIter<'a, T> {} #[cfg(feature = "serialize")] @@ -740,7 +734,7 @@ impl<'de> Deserialize<'de> for BuiltDisplayList { Debug::PopReferenceFrame => Real::PopReferenceFrame, Debug::PopAllShadows => Real::PopAllShadows, }; - serialize_fast(&mut data, &item); + poke_into_vec(&item, &mut data); // the aux data is serialized after the item, hence the temporary data.extend(temp.drain(..)); } @@ -758,221 +752,6 @@ impl<'de> Deserialize<'de> for BuiltDisplayList { } } -// This is a replacement for bincode::serialize_into(&vec) -// The default implementation Write for Vec will basically -// call extend_from_slice(). Serde ends up calling that for every -// field of a struct that we're serializing. extend_from_slice() -// does not get inlined and thus we end up calling a generic memcpy() -// implementation. If we instead reserve enough room for the serialized -// struct in the Vec ahead of time we can rely on that and use -// the following UnsafeVecWriter to write into the vec without -// any checks. This writer assumes that size returned by the -// serialize function will not change between calls to serialize_into: -// -// For example, the following struct will cause memory unsafety when -// used with UnsafeVecWriter. -// -// struct S { -// first: Cell, -// } -// -// impl Serialize for S { -// fn serialize(&self, serializer: S) -> Result -// where S: Serializer -// { -// if self.first.get() { -// self.first.set(false); -// ().serialize(serializer) -// } else { -// 0.serialize(serializer) -// } -// } -// } -// - -struct UnsafeVecWriter(*mut u8); - -impl Write for UnsafeVecWriter { - #[inline(always)] - fn write(&mut self, buf: &[u8]) -> io::Result { - unsafe { - ptr::copy_nonoverlapping(buf.as_ptr(), self.0, buf.len()); - self.0 = self.0.add(buf.len()); - } - Ok(buf.len()) - } - - #[inline(always)] - fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { - unsafe { - ptr::copy_nonoverlapping(buf.as_ptr(), self.0, buf.len()); - self.0 = self.0.add(buf.len()); - } - Ok(()) - } - - #[inline(always)] - fn flush(&mut self) -> io::Result<()> { Ok(()) } -} - -struct SizeCounter(usize); - -impl<'a> Write for SizeCounter { - #[inline(always)] - fn write(&mut self, buf: &[u8]) -> io::Result { - self.0 += buf.len(); - Ok(buf.len()) - } - - #[inline(always)] - fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { - self.0 += buf.len(); - Ok(()) - } - - #[inline(always)] - fn flush(&mut self) -> io::Result<()> { Ok(()) } -} - -/// Serializes a value assuming the Serialize impl has a stable size across two -/// invocations. -/// -/// If this assumption is incorrect, the result will be Undefined Behaviour. This -/// assumption should hold for all derived Serialize impls, which is all we currently -/// use. -fn serialize_fast(vec: &mut Vec, e: T) { - // manually counting the size is faster than vec.reserve(bincode::serialized_size(&e) as usize) for some reason - let mut size = SizeCounter(0); - bincode::serialize_into(&mut size, &e).unwrap(); - vec.reserve(size.0); - - let old_len = vec.len(); - let ptr = unsafe { vec.as_mut_ptr().add(old_len) }; - let mut w = UnsafeVecWriter(ptr); - bincode::serialize_into(&mut w, &e).unwrap(); - - // fix up the length - unsafe { vec.set_len(old_len + size.0); } - - // make sure we wrote the right amount - debug_assert_eq!(((w.0 as usize) - (vec.as_ptr() as usize)), vec.len()); -} - -/// Serializes an iterator, assuming: -/// -/// * The Clone impl is trivial (e.g. we're just memcopying a slice iterator) -/// * The ExactSizeIterator impl is stable and correct across a Clone -/// * The Serialize impl has a stable size across two invocations -/// -/// If the first is incorrect, WebRender will be very slow. If the other two are -/// incorrect, the result will be Undefined Behaviour! The ExactSizeIterator -/// bound would ideally be replaced with a TrustedLen bound to protect us a bit -/// better, but that trait isn't stable (and won't be for a good while, if ever). -/// -/// Debug asserts are included that should catch all Undefined Behaviour, but -/// we can't afford to include these in release builds. -fn serialize_iter_fast(vec: &mut Vec, iter: I) -> usize -where I: ExactSizeIterator + Clone, - I::Item: Serialize, -{ - // manually counting the size is faster than vec.reserve(bincode::serialized_size(&e) as usize) for some reason - let mut size = SizeCounter(0); - let mut count1 = 0; - - for e in iter.clone() { - bincode::serialize_into(&mut size, &e).unwrap(); - count1 += 1; - } - - vec.reserve(size.0); - - let old_len = vec.len(); - let ptr = unsafe { vec.as_mut_ptr().add(old_len) }; - let mut w = UnsafeVecWriter(ptr); - let mut count2 = 0; - - for e in iter { - bincode::serialize_into(&mut w, &e).unwrap(); - count2 += 1; - } - - // fix up the length - unsafe { vec.set_len(old_len + size.0); } - - // make sure we wrote the right amount - debug_assert_eq!(((w.0 as usize) - (vec.as_ptr() as usize)), vec.len()); - debug_assert_eq!(count1, count2); - - count1 -} - -// This uses a (start, end) representation instead of (start, len) so that -// only need to update a single field as we read through it. This -// makes it easier for llvm to understand what's going on. (https://github.com/rust-lang/rust/issues/45068) -// We update the slice only once we're done reading -struct UnsafeReader<'a: 'b, 'b> { - start: *const u8, - end: *const u8, - slice: &'b mut &'a [u8], -} - -impl<'a, 'b> UnsafeReader<'a, 'b> { - #[inline(always)] - fn new(buf: &'b mut &'a [u8]) -> UnsafeReader<'a, 'b> { - unsafe { - let end = buf.as_ptr().add(buf.len()); - let start = buf.as_ptr(); - UnsafeReader { start, end, slice: buf } - } - } - - // This read implementation is significantly faster than the standard &[u8] one. - // - // First, it only supports reading exactly buf.len() bytes. This ensures that - // the argument to memcpy is always buf.len() and will allow a constant buf.len() - // to be propagated through to memcpy which LLVM will turn into explicit loads and - // stores. The standard implementation does a len = min(slice.len(), buf.len()) - // - // Second, we only need to adjust 'start' after reading and it's only adjusted by a - // constant. This allows LLVM to avoid adjusting the length field after ever read - // and lets it be aggregated into a single adjustment. - #[inline(always)] - fn read_internal(&mut self, buf: &mut [u8]) { - // this is safe because we panic if start + buf.len() > end - unsafe { - assert!(self.start.add(buf.len()) <= self.end, "UnsafeReader: read past end of target"); - ptr::copy_nonoverlapping(self.start, buf.as_mut_ptr(), buf.len()); - self.start = self.start.add(buf.len()); - } - } -} - -impl<'a, 'b> Drop for UnsafeReader<'a, 'b> { - // this adjusts input slice so that it properly represents the amount that's left. - #[inline(always)] - fn drop(&mut self) { - // this is safe because we know that start and end are contained inside the original slice - unsafe { - *self.slice = slice::from_raw_parts(self.start, (self.end as usize) - (self.start as usize)); - } - } -} - -impl<'a, 'b> Read for UnsafeReader<'a, 'b> { - // These methods were not being inlined and we need them to be so that the memcpy - // is for a constant size - #[inline(always)] - fn read(&mut self, buf: &mut [u8]) -> io::Result { - self.read_internal(buf); - Ok(buf.len()) - } - #[inline(always)] - fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { - self.read_internal(buf); - Ok(()) - } -} - #[derive(Clone, Debug)] pub struct SaveState { dl_len: usize, @@ -1108,38 +887,39 @@ impl DisplayListBuilder { /// result in WebRender panicking or behaving in unexpected ways. #[inline] pub fn push_item(&mut self, item: &di::DisplayItem) { - serialize_fast(&mut self.data, item); + poke_into_vec(item, &mut self.data); } fn push_iter_impl(data: &mut Vec, iter_source: I) where I: IntoIterator, - I::IntoIter: ExactSizeIterator + Clone, - I::Item: Serialize, + I::IntoIter: ExactSizeIterator, + I::Item: Poke, { let iter = iter_source.into_iter(); let len = iter.len(); // Format: // payload_byte_size: usize, item_count: usize, [I; item_count] - // We write a dummy value so there's room for later + // Track the the location of where to write byte size with offsets + // instead of pointers because data may be moved in memory during + // `serialize_iter_fast`. let byte_size_offset = data.len(); - serialize_fast(data, &0usize); - let payload_offset = data.len(); - serialize_fast(data, &len); - let count = serialize_iter_fast(data, iter); + + // We write a dummy value so there's room for later + poke_into_vec(&0usize, data); + poke_into_vec(&len, data); + let count = poke_extend_vec(iter, data); + debug_assert_eq!(len, count); + + // Add red zone + ensure_red_zone::(data); // Now write the actual byte_size let final_offset = data.len(); - let byte_size = final_offset - payload_offset; - - // Note we don't use serialize_fast because we don't want to change the Vec's len - bincode::serialize_into( - &mut &mut data[byte_size_offset..], - &byte_size, - ).unwrap(); - - debug_assert_eq!(len, count); + debug_assert!(final_offset >= (byte_size_offset + mem::size_of::())); + let byte_size = final_offset - byte_size_offset - mem::size_of::(); + poke_inplace_slice(&byte_size, &mut data[byte_size_offset..]); } /// Push items from an iterator to the display list. @@ -1149,8 +929,8 @@ impl DisplayListBuilder { pub fn push_iter(&mut self, iter: I) where I: IntoIterator, - I::IntoIter: ExactSizeIterator + Clone, - I::Item: Serialize, + I::IntoIter: ExactSizeIterator, + I::Item: Poke, { Self::push_iter_impl(&mut self.data, iter); } @@ -1684,9 +1464,14 @@ impl DisplayListBuilder { self.push_item(&di::DisplayItem::PopAllShadows); } - pub fn finalize(self) -> (PipelineId, LayoutSize, BuiltDisplayList) { + pub fn finalize(mut self) -> (PipelineId, LayoutSize, BuiltDisplayList) { assert!(self.save_state.is_none(), "Finalized DisplayListBuilder with a pending save"); + // Add `DisplayItem::max_size` zone of zeroes to the end of display list + // so there is at least this amount available in the display list during + // serialization. + ensure_red_zone::(&mut self.data); + let end_time = precise_time_ns(); ( diff --git a/gfx/wr/webrender_api/src/font.rs b/gfx/wr/webrender_api/src/font.rs index 4861e406a9c4..fa099baa71c1 100644 --- a/gfx/wr/webrender_api/src/font.rs +++ b/gfx/wr/webrender_api/src/font.rs @@ -7,6 +7,7 @@ use app_units::Au; use core_foundation::string::CFString; #[cfg(target_os = "macos")] use core_graphics::font::CGFont; +use peek_poke::PeekPoke; #[cfg(target_os = "macos")] use serde::de::{self, Deserialize, Deserializer}; #[cfg(target_os = "macos")] @@ -97,13 +98,19 @@ pub enum FontTemplate { } #[repr(u8)] -#[derive(Debug, Copy, Clone, Hash, Eq, MallocSizeOf, PartialEq, Serialize, Deserialize, Ord, PartialOrd)] +#[derive(Debug, Copy, Clone, Hash, Eq, MallocSizeOf, PartialEq, Serialize, Deserialize, Ord, PartialOrd, PeekPoke)] pub enum FontRenderMode { Mono = 0, Alpha, Subpixel, } +impl Default for FontRenderMode { + fn default() -> Self { + FontRenderMode::Mono + } +} + impl FontRenderMode { // Combine two font render modes such that the lesser amount of AA limits the AA of the result. pub fn limit_by(self, other: FontRenderMode) -> FontRenderMode { @@ -145,7 +152,7 @@ impl Hash for FontVariation { } #[repr(C)] -#[derive(Clone, Copy, Debug, Deserialize, Hash, Eq, PartialEq, PartialOrd, Ord, Serialize)] +#[derive(Clone, Copy, Debug, Deserialize, Hash, Eq, PartialEq, PartialOrd, Ord, Serialize, PeekPoke)] pub struct GlyphOptions { pub render_mode: FontRenderMode, pub flags: FontInstanceFlags, @@ -162,7 +169,7 @@ impl Default for GlyphOptions { bitflags! { #[repr(C)] - #[derive(Deserialize, MallocSizeOf, Serialize)] + #[derive(Deserialize, MallocSizeOf, Serialize, PeekPoke)] pub struct FontInstanceFlags: u32 { // Common flags const SYNTHETIC_BOLD = 1 << 1; @@ -348,7 +355,8 @@ impl Default for FontInstancePlatformOptions { } #[repr(C)] -#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize, Ord, PartialOrd, MallocSizeOf)] +#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq, Ord, PartialOrd, MallocSizeOf, PeekPoke)] +#[derive(Deserialize, Serialize)] pub struct FontInstanceKey(pub IdNamespace, pub u32); impl FontInstanceKey { @@ -373,12 +381,21 @@ pub struct FontInstanceData { pub type GlyphIndex = u32; #[repr(C)] -#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize, PeekPoke)] pub struct GlyphInstance { pub index: GlyphIndex, pub point: LayoutPoint, } +impl Default for GlyphInstance { + fn default() -> Self { + GlyphInstance { + index: 0, + point: LayoutPoint::zero(), + } + } +} + impl Eq for GlyphInstance {} impl Hash for GlyphInstance { diff --git a/gfx/wr/webrender_api/src/image.rs b/gfx/wr/webrender_api/src/image.rs index e3c7e382f7a7..54110da922ab 100644 --- a/gfx/wr/webrender_api/src/image.rs +++ b/gfx/wr/webrender_api/src/image.rs @@ -5,6 +5,7 @@ #![deny(missing_docs)] use euclid::{size2, TypedRect, num::Zero}; +use peek_poke::PeekPoke; use std::ops::{Add, Sub}; use std::sync::Arc; // local imports @@ -16,9 +17,15 @@ use crate::units::*; /// This is used as a handle to reference images, and is used as the /// hash map key for the actual image storage in the `ResourceCache`. #[repr(C)] -#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)] pub struct ImageKey(pub IdNamespace, pub u32); +impl Default for ImageKey { + fn default() -> Self { + ImageKey::DUMMY + } +} + impl ImageKey { /// Placeholder Image key, used to represent None. pub const DUMMY: Self = ImageKey(IdNamespace(0), 0); @@ -142,7 +149,7 @@ impl ImageFormat { /// Specifies the color depth of an image. Currently only used for YUV images. #[repr(u8)] -#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)] pub enum ColorDepth { /// 8 bits image (most common) Color8, @@ -154,6 +161,12 @@ pub enum ColorDepth { Color16, } +impl Default for ColorDepth { + fn default() -> Self { + ColorDepth::Color8 + } +} + impl ColorDepth { /// Return the numerical bit depth value for the type. pub fn bit_depth(self) -> u32 { diff --git a/gfx/wr/webrender_api/src/lib.rs b/gfx/wr/webrender_api/src/lib.rs index 3537deae42a0..f75c9eed586a 100644 --- a/gfx/wr/webrender_api/src/lib.rs +++ b/gfx/wr/webrender_api/src/lib.rs @@ -15,7 +15,6 @@ #![cfg_attr(feature = "cargo-clippy", allow(float_cmp, too_many_arguments, unreadable_literal))] extern crate app_units; -extern crate bincode; #[macro_use] extern crate bitflags; extern crate byteorder; @@ -38,6 +37,7 @@ extern crate serde_derive; extern crate time; extern crate malloc_size_of; +extern crate peek_poke; mod api; pub mod channel; diff --git a/gfx/wr/webrender_api/src/units.rs b/gfx/wr/webrender_api/src/units.rs index b43cc0fba31d..c3945b256341 100644 --- a/gfx/wr/webrender_api/src/units.rs +++ b/gfx/wr/webrender_api/src/units.rs @@ -16,6 +16,7 @@ pub use app_units::Au; use euclid::{Length, TypedRect, TypedScale, TypedSize2D, TypedTransform3D, TypedTranslation2D}; use euclid::{TypedPoint2D, TypedPoint3D, TypedVector2D, TypedVector3D, TypedSideOffsets2D}; use euclid::HomogeneousVector; +use peek_poke::PeekPoke; // local imports use crate::image::DirtyRect; @@ -77,7 +78,7 @@ pub type RasterVector2D = TypedVector2D; pub type RasterVector3D = TypedVector3D; /// Geometry in a stacking context's local coordinate space (logical pixels). -#[derive(Hash, Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, Ord, PartialOrd, Deserialize, Serialize)] +#[derive(Hash, Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, Ord, PartialOrd, Deserialize, Serialize, PeekPoke)] pub struct LayoutPixel; pub type LayoutRect = TypedRect; diff --git a/js/public/UbiNodeBreadthFirst.h b/js/public/UbiNodeBreadthFirst.h index d8433f129c89..2f269fbf3736 100644 --- a/js/public/UbiNodeBreadthFirst.h +++ b/js/public/UbiNodeBreadthFirst.h @@ -65,6 +65,11 @@ namespace ubi { // Note that |abandonReferent| must be called the first time the given node // is reached; that is, |first| must be true. // +// The visitor function may call |doNotMarkReferentAsVisited()| if it +// does not want a node to be considered 'visited' (and added to the +// 'visited' set). This is useful when the visitor has custom logic to +// determine whether an edge is 'interesting'. +// // The visitor function may call |traversal.stop()| if it doesn't want // to visit any more nodes at all. // @@ -91,7 +96,8 @@ struct BreadthFirst { pending(), traversalBegun(false), stopRequested(false), - abandonRequested(false) {} + abandonRequested(false), + markReferentAsVisited(false) {} // Add |node| as a starting point for the traversal. You may add // as many starting points as you like. Return false on OOM. @@ -141,21 +147,26 @@ struct BreadthFirst { typename NodeMap::AddPtr a = visited.lookupForAdd(edge.referent); bool first = !a; - if (first) { - // This is the first time we've reached |edge.referent|. - // Mark it as visited. - if (!visited.add(a, edge.referent, typename Handler::NodeData())) { - return false; - } - } - - MOZ_ASSERT(a); + // Pass a pointer to a stack-allocated NodeData if the referent is not + // in |visited|. + typename Handler::NodeData nodeData; + typename Handler::NodeData* nodeDataPtr = + first ? &nodeData : &a->value(); // Report this edge to the visitor function. - if (!handler(*this, origin, edge, &a->value(), first)) { + markReferentAsVisited = true; + if (!handler(*this, origin, edge, nodeDataPtr, first)) { return false; } + if (first && markReferentAsVisited) { + // This is the first time we've reached |edge.referent| and the + // handler wants it marked as visited. + if (!visited.add(a, edge.referent, std::move(nodeData))) { + return false; + } + } + if (stopRequested) { return true; } @@ -188,6 +199,10 @@ struct BreadthFirst { // Other edges *to* that referent will still be traversed. void abandonReferent() { abandonRequested = true; } + // Request the the current edge's referent not be added to the |visited| set + // if this is the first time we're visiting it. + void doNotMarkReferentAsVisited() { markReferentAsVisited = false; } + // The context with which we were constructed. JSContext* cx; @@ -244,6 +259,10 @@ struct BreadthFirst { // True if we've been asked to abandon the current edge's referent. bool abandonRequested; + + // True if the node should be added to the |visited| set after calling the + // handler. + bool markReferentAsVisited; }; } // namespace ubi diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp index 70b29c35443b..2a69860776c6 100644 --- a/js/src/builtin/TestingFunctions.cpp +++ b/js/src/builtin/TestingFunctions.cpp @@ -3676,7 +3676,7 @@ struct FindPathHandler { // Have we reached our final target node? if (edge.referent == target) { // Record the path that got us here, which must be a shortest path. - if (!recordPath(traversal)) { + if (!recordPath(traversal, backEdge)) { return false; } foundPath = true; @@ -3689,17 +3689,24 @@ struct FindPathHandler { // We've found a path to our target. Walk the backlinks to produce the // (reversed) path, saving the path in |nodes| and |edges|. |nodes| is // rooted, so it can hold the path's nodes as we leave the scope of - // the AutoCheckCannotGC. - bool recordPath(Traversal& traversal) { + // the AutoCheckCannotGC. Note that nodes are added to |visited| after we + // return from operator() so we have to pass the target BackEdge* to this + // function. + bool recordPath(Traversal& traversal, BackEdge* targetBackEdge) { JS::ubi::Node here = target; do { - Traversal::NodeMap::Ptr p = traversal.visited.lookup(here); - MOZ_ASSERT(p); - JS::ubi::Node predecessor = p->value().predecessor(); + BackEdge* backEdge = targetBackEdge; + if (here != target) { + Traversal::NodeMap::Ptr p = traversal.visited.lookup(here); + MOZ_ASSERT(p); + backEdge = &p->value(); + } + JS::ubi::Node predecessor = backEdge->predecessor(); if (!nodes.append(predecessor.exposeToJS()) || - !edges.append(p->value().forgetName())) + !edges.append(backEdge->forgetName())) { return false; + } here = predecessor; } while (here != start); diff --git a/js/src/gc/Nursery.cpp b/js/src/gc/Nursery.cpp index cb7e8db61e38..91b9261e882c 100644 --- a/js/src/gc/Nursery.cpp +++ b/js/src/gc/Nursery.cpp @@ -69,7 +69,7 @@ struct NurseryChunk { static_assert(sizeof(js::NurseryChunk) == gc::ChunkSize, "Nursery chunk size must match gc::Chunk size."); -} /* namespace js */ +} // namespace js inline void js::NurseryChunk::poisonAndInit(JSRuntime* rt, size_t size) { poisonRange(0, size, JS_FRESH_NURSERY_PATTERN, MemCheckKind::MakeUndefined); @@ -96,7 +96,7 @@ inline void js::NurseryChunk::poisonAfterEvict(size_t extent) { poisonRange(0, extent, JS_SWEPT_NURSERY_PATTERN, MemCheckKind::MakeNoAccess); } -/* static */ +// static inline js::NurseryChunk* js::NurseryChunk::fromChunk(Chunk* chunk) { return reinterpret_cast(chunk); } @@ -235,10 +235,10 @@ bool js::Nursery::init(uint32_t maxNurseryBytes, AutoLockGCBgAlloc& lock) { maxNurseryBytes = 0; } - /* maxNurseryBytes parameter is rounded down to a multiple of chunk size. */ + // maxNurseryBytes parameter is rounded down to a multiple of chunk size. chunkCountLimit_ = maxNurseryBytes >> ChunkShift; - /* If no chunks are specified then the nursery is permanently disabled. */ + // If no chunks are specified then the nursery is permanently disabled. if (chunkCountLimit_ == 0) { return true; } @@ -248,7 +248,7 @@ bool js::Nursery::init(uint32_t maxNurseryBytes, AutoLockGCBgAlloc& lock) { } capacity_ = roundSize(tunables().gcMinNurseryBytes()); MOZ_ASSERT(capacity_ >= ArenaSize); - /* After this point the Nursery has been enabled */ + // After this point the Nursery has been enabled. setCurrentChunk(0); setStartPosition(); @@ -326,7 +326,7 @@ void js::Nursery::disable() { capacity_ = 0; // We must reset currentEnd_ so that there is no space for anything in the - // nursery. JIT'd code uses this even if the nursery is disabled. + // nursery. JIT'd code uses this even if the nursery is disabled. currentEnd_ = 0; currentStringEnd_ = 0; position_ = 0; @@ -596,7 +596,7 @@ void* js::Nursery::reallocateBuffer(JSObject* obj, void* oldBuffer, return newBuffer; } - /* The nursery cannot make use of the returned slots data. */ + // The nursery cannot make use of the returned slots data. if (newBytes < oldBytes) { return oldBuffer; } @@ -682,10 +682,8 @@ inline float js::Nursery::calcPromotionRate(bool* validForTenuring) const { if (previousGC.nurseryUsedBytes > 0) { if (validForTenuring) { - /* - * We can only use promotion rates if they're likely to be valid, - * they're only valid if the nursury was at least 90% full. - */ + // We can only use promotion rates if they're likely to be valid, + // they're only valid if the nursery was at least 90% full. *validForTenuring = used > capacity * 0.9f; } rate = tenured / used; @@ -777,7 +775,7 @@ void js::Nursery::renderProfileJSON(JSONPrinter& json) const { json.endObject(); } -/* static */ +// static void js::Nursery::printProfileHeader() { fprintf(stderr, "MinorGC: Reason PRate Size "); #define PRINT_HEADER(name, text) fprintf(stderr, " %6s", text); @@ -786,7 +784,7 @@ void js::Nursery::printProfileHeader() { fprintf(stderr, "\n"); } -/* static */ +// static void js::Nursery::printProfileDurations(const ProfileDurations& times) { for (auto time : times) { fprintf(stderr, " %6" PRIi64, static_cast(time.ToMicroseconds())); @@ -832,14 +830,14 @@ bool js::Nursery::shouldCollect() const { // and belowFractionThreshold when it's small. // // When the nursery is small then belowBytesThreshold is a lower threshold - // (triggered earlier) than belowFractionThreshold. So if the fraction - // threshold is true, the bytes one will be true also. The opposite is true + // (triggered earlier) than belowFractionThreshold. So if the fraction + // threshold is true, the bytes one will be true also. The opposite is true // when the nursery is large. // // Therefore, by the time we cross the threshold we care about, we've already // crossed the other one, and we can boolean AND to use either condition - // without encoding any "is the nursery big/small" test/threshold. The point - // at which they cross is when the nursery is: BytesThreshold / + // without encoding any "is the nursery big/small" test/threshold. The point + // at which they cross is when the nursery is: BytesThreshold / // FractionThreshold large. // // With defaults that's: @@ -1230,10 +1228,8 @@ void js::Nursery::clear() { .poisonAfterEvict(position() - chunk(currentChunk_).start()); } - /* - * Reset the start chunk & position if we're not in this zeal mode, or we're - * in it and close to the end of the nursery. - */ + // Reset the start chunk & position if we're not in this zeal mode, or we're + // in it and close to the end of the nursery. MOZ_ASSERT(maxChunkCount() > 0); if (!runtime()->hasZealMode(ZealMode::GenerationalGC) || (runtime()->hasZealMode(ZealMode::GenerationalGC) && @@ -1241,7 +1237,7 @@ void js::Nursery::clear() { setCurrentChunk(0); } - /* Set current start position for isEmpty checks. */ + // Set current start position for isEmpty checks. setStartPosition(); } @@ -1342,19 +1338,15 @@ void js::Nursery::maybeResizeNursery(JS::GCReason reason) { return; } - /* - * This incorrect promotion rate results in better nursery sizing - * decisions, however we should to better tuning based on the real - * promotion rate in the future. - */ + // This incorrect promotion rate results in better nursery sizing + // decisions, however we should to better tuning based on the real + // promotion rate in the future. const float promotionRate = float(previousGC.tenuredBytes) / float(previousGC.nurseryCapacity); - /* - * Object lifetimes aren't going to behave linearly, but a better - * relationship that works for all programs and can be predicted in - * advance doesn't exist. - */ + // Object lifetimes aren't going to behave linearly, but a better + // relationship that works for all programs and can be predicted in + // advance doesn't exist. static const float GrowThreshold = 0.03f; static const float ShrinkThreshold = 0.01f; static const float PromotionGoal = (GrowThreshold + ShrinkThreshold) / 2.0f; @@ -1368,7 +1360,7 @@ void js::Nursery::maybeResizeNursery(JS::GCReason reason) { MOZ_ASSERT(minNurseryBytes >= ArenaSize); // If one of these conditions is true then we always shrink or grow the - // nursery. This way the thresholds still have an effect even if the goal + // nursery. This way the thresholds still have an effect even if the goal // seeking says the current size is ideal. size_t lowLimit = Max(minNurseryBytes, capacity() / 2); size_t highLimit = @@ -1424,9 +1416,9 @@ bool js::Nursery::maybeResizeExact(JS::GCReason reason) { } if (newMaxNurseryChunks != chunkCountLimit_) { chunkCountLimit_ = newMaxNurseryChunks; - /* The configured maximum nursery size is changing */ + // The configured maximum nursery size is changing. if (JS_HOWMANY(capacity_, gc::ChunkSize) > newMaxNurseryChunks) { - /* We need to shrink the nursery */ + // We need to shrink the nursery. static_assert(NurseryChunkUsableSize < ChunkSize, "Usable size must be smaller than total size or this " "calculation might overflow"); @@ -1439,10 +1431,7 @@ bool js::Nursery::maybeResizeExact(JS::GCReason reason) { MOZ_ASSERT(minNurseryBytes >= ArenaSize); if (minNurseryBytes > capacity()) { - /* - * the configured minimum nursery size is changing and we need to grow the - * nursery - */ + // the configured minimum nursery size is changing, so grow the nursery. MOZ_ASSERT(minNurseryBytes <= roundSize(tunables().gcMaxNurseryBytes())); growAllocableSpace(minNurseryBytes); return true; diff --git a/js/src/gc/Nursery.h b/js/src/gc/Nursery.h index b5b4644ae191..6528cd0fb88e 100644 --- a/js/src/gc/Nursery.h +++ b/js/src/gc/Nursery.h @@ -67,7 +67,7 @@ class RelocationOverlay; struct TenureCountCache; enum class AllocKind : uint8_t; class TenuredCell; -} /* namespace gc */ +} // namespace gc namespace jit { class MacroAssembler; @@ -151,13 +151,11 @@ class TenuringTracer : public JSTracer { void traceSlots(JS::Value* vp, JS::Value* end); }; -/* - * Classes with JSCLASS_SKIP_NURSERY_FINALIZE or Wrapper classes with - * CROSS_COMPARTMENT flags will not have their finalizer called if they are - * nursery allocated and not promoted to the tenured heap. The finalizers for - * these classes must do nothing except free data which was allocated via - * Nursery::allocateBuffer. - */ +// Classes with JSCLASS_SKIP_NURSERY_FINALIZE or Wrapper classes with +// CROSS_COMPARTMENT flags will not have their finalizer called if they are +// nursery allocated and not promoted to the tenured heap. The finalizers for +// these classes must do nothing except free data which was allocated via +// Nursery::allocateBuffer. inline bool CanNurseryAllocateFinalizedClass(const js::Class* const clasp) { MOZ_ASSERT(clasp->hasFinalize()); return clasp->flags & JSCLASS_SKIP_NURSERY_FINALIZE; @@ -168,9 +166,7 @@ class Nursery { static const size_t Alignment = gc::ChunkSize; static const size_t ChunkShift = gc::ChunkShift; - /* - * SubChunkStep is the minimum amount to adjust the nursery's size by. - */ + // SubChunkStep is the minimum amount to adjust the nursery's size by. static const size_t SubChunkStep = gc::ArenaSize; struct alignas(gc::CellAlignBytes) CellAlignedByte { @@ -213,13 +209,11 @@ class Nursery { void disableStrings(); bool canAllocateStrings() const { return canAllocateStrings_; } - /* Return true if no allocations have been made since the last collection. */ + // Return true if no allocations have been made since the last collection. bool isEmpty() const; - /* - * Check whether an arbitrary pointer is within the nursery. This is - * slower than IsInsideNursery(Cell*), but works on all types of pointers. - */ + // Check whether an arbitrary pointer is within the nursery. This is + // slower than IsInsideNursery(Cell*), but works on all types of pointers. MOZ_ALWAYS_INLINE bool isInside(gc::Cell* cellp) const = delete; MOZ_ALWAYS_INLINE bool isInside(const void* p) const { for (auto chunk : chunks_) { @@ -233,22 +227,16 @@ class Nursery { template inline bool isInside(const SharedMem& p) const; - /* - * Allocate and return a pointer to a new GC object with its |slots| - * pointer pre-filled. Returns nullptr if the Nursery is full. - */ + // Allocate and return a pointer to a new GC object with its |slots| + // pointer pre-filled. Returns nullptr if the Nursery is full. JSObject* allocateObject(JSContext* cx, size_t size, size_t numDynamic, const js::Class* clasp); - /* - * Allocate and return a pointer to a new string. Returns nullptr if the - * Nursery is full. - */ + // Allocate and return a pointer to a new string. Returns nullptr if the + // Nursery is full. gc::Cell* allocateString(JS::Zone* zone, size_t size, gc::AllocKind kind); - /* - * String zones are stored just before the string in nursery memory. - */ + // String zones are stored just before the string in nursery memory. static JS::Zone* getStringZone(const JSString* str) { #ifdef DEBUG auto cell = reinterpret_cast( @@ -264,59 +252,50 @@ class Nursery { static size_t stringHeaderSize() { return offsetof(StringLayout, cell); } - /* Allocate a buffer for a given zone, using the nursery if possible. */ + // Allocate a buffer for a given zone, using the nursery if possible. void* allocateBuffer(JS::Zone* zone, size_t nbytes); - /* - * Allocate a buffer for a given object, using the nursery if possible and - * obj is in the nursery. - */ + // Allocate a buffer for a given object, using the nursery if possible and + // obj is in the nursery. void* allocateBuffer(JSObject* obj, size_t nbytes); - /* - * Allocate a buffer for a given object, always using the nursery if obj is - * in the nursery. The requested size must be less than or equal to - * MaxNurseryBufferSize. - */ + // Allocate a buffer for a given object, always using the nursery if obj is + // in the nursery. The requested size must be less than or equal to + // MaxNurseryBufferSize. void* allocateBufferSameLocation(JSObject* obj, size_t nbytes); - /* Allocate a zero-initialized buffer for a given zone, using the nursery if - * possible. If the buffer isn't allocated in the nursery, the given arena is - * used. - */ + // Allocate a zero-initialized buffer for a given zone, using the nursery if + // possible. If the buffer isn't allocated in the nursery, the given arena is + // used. void* allocateZeroedBuffer(JS::Zone* zone, size_t nbytes, arena_id_t arena = js::MallocArena); - /* - * Allocate a zero-initialized buffer for a given object, using the nursery if - * possible and obj is in the nursery. If the buffer isn't allocated in the - * nursery, the given arena is used. - */ + // Allocate a zero-initialized buffer for a given object, using the nursery if + // possible and obj is in the nursery. If the buffer isn't allocated in the + // nursery, the given arena is used. void* allocateZeroedBuffer(JSObject* obj, size_t nbytes, arena_id_t arena = js::MallocArena); - /* Resize an existing object buffer. */ + // Resize an existing object buffer. void* reallocateBuffer(JSObject* obj, void* oldBuffer, size_t oldBytes, size_t newBytes); - /* Free an object buffer. */ + // Free an object buffer. void freeBuffer(void* buffer); - /* The maximum number of bytes allowed to reside in nursery buffers. */ + // The maximum number of bytes allowed to reside in nursery buffers. static const size_t MaxNurseryBufferSize = 1024; - /* Do a minor collection. */ + // Do a minor collection. void collect(JS::GCReason reason); - /* - * If the thing at |*ref| in the Nursery has been forwarded, set |*ref| to - * the new location and return true. Otherwise return false and leave - * |*ref| unset. - */ + // If the thing at |*ref| in the Nursery has been forwarded, set |*ref| to + // the new location and return true. Otherwise return false and leave + // |*ref| unset. MOZ_ALWAYS_INLINE MOZ_MUST_USE static bool getForwardedPointer( js::gc::Cell** ref); - /* Forward a slots/elements pointer stored in an Ion frame. */ + // Forward a slots/elements pointer stored in an Ion frame. void forwardBufferPointer(HeapSlot** pSlotsElems); inline void maybeSetForwardingPointer(JSTracer* trc, void* oldData, @@ -324,14 +303,12 @@ class Nursery { inline void setForwardingPointerWhileTenuring(void* oldData, void* newData, bool direct); - /* - * Register a malloced buffer that is held by a nursery object, which - * should be freed at the end of a minor GC. Buffers are unregistered when - * their owning objects are tenured. - */ + // Register a malloced buffer that is held by a nursery object, which + // should be freed at the end of a minor GC. Buffers are unregistered when + // their owning objects are tenured. bool registerMallocedBuffer(void* buffer); - /* Mark a malloced buffer as no longer needing to be freed. */ + // Mark a malloced buffer as no longer needing to be freed. void removeMallocedBuffer(void* buffer) { MOZ_ASSERT(mallocedBuffers.has(buffer)); mallocedBuffers.remove(buffer); @@ -387,13 +364,13 @@ class Nursery { void leaveZealMode(); #endif - /* Write profile time JSON on JSONPrinter. */ + // Write profile time JSON on JSONPrinter. void renderProfileJSON(JSONPrinter& json) const; - /* Print header line for profile times. */ + // Print header line for profile times. static void printProfileHeader(); - /* Print total profile times on shutdown. */ + // Print total profile times on shutdown. void printTotalProfileTimes(); void* addressOfPosition() const { return (void**)&position_; } @@ -427,7 +404,7 @@ class Nursery { return setsWithNurseryMemory_.append(obj); } - /* The amount of space in the mapped nursery available to allocations. */ + // The amount of space in the mapped nursery available to allocations. static const size_t NurseryChunkUsableSize = gc::ChunkSize - gc::ChunkTrailerSize; @@ -436,66 +413,56 @@ class Nursery { private: JSRuntime* runtime_; - /* Vector of allocated chunks to allocate from. */ + // Vector of allocated chunks to allocate from. Vector chunks_; - /* Pointer to the first unallocated byte in the nursery. */ + // Pointer to the first unallocated byte in the nursery. uintptr_t position_; - /* - * These fields refer to the beginning of the nursery. They're normally 0 - * and chunk(0).start() respectively. Except when a generational GC zeal - * mode is active, then they may be arbitrary (see Nursery::clear()). - */ + // These fields refer to the beginning of the nursery. They're normally 0 + // and chunk(0).start() respectively. Except when a generational GC zeal + // mode is active, then they may be arbitrary (see Nursery::clear()). unsigned currentStartChunk_; uintptr_t currentStartPosition_; - /* Pointer to the last byte of space in the current chunk. */ + // Pointer to the last byte of space in the current chunk. uintptr_t currentEnd_; - /* - * Pointer to the last byte of space in the current chunk, or nullptr if we - * are not allocating strings in the nursery. - */ + // Pointer to the last byte of space in the current chunk, or nullptr if we + // are not allocating strings in the nursery. uintptr_t currentStringEnd_; - /* The index of the chunk that is currently being allocated from. */ + // The index of the chunk that is currently being allocated from. unsigned currentChunk_; - /* - * The current nursery capacity measured in bytes. It may grow up to this - * value without a collection, allocating chunks on demand. This limit may be - * changed by maybeResizeNursery() each collection. It does not include chunk - * trailers. - */ + // The current nursery capacity measured in bytes. It may grow up to this + // value without a collection, allocating chunks on demand. This limit may be + // changed by maybeResizeNursery() each collection. It does not include chunk + // trailers. size_t capacity_; - /* - * This limit is fixed by configuration. It represents the maximum size - * the nursery is permitted to tune itself to in maybeResizeNursery(); - */ + // This limit is fixed by configuration. It represents the maximum size + // the nursery is permitted to tune itself to in maybeResizeNursery(); unsigned chunkCountLimit_; mozilla::TimeDuration timeInChunkAlloc_; - /* Report minor collections taking at least this long, if enabled. */ + // Report minor collections taking at least this long, if enabled. mozilla::TimeDuration profileThreshold_; bool enableProfiling_; - /* Whether we will nursery-allocate strings. */ + // Whether we will nursery-allocate strings. bool canAllocateStrings_; - /* Report ObjectGroups with at least this many instances tenured. */ + // Report ObjectGroups with at least this many instances tenured. int64_t reportTenurings_; - /* - * Whether and why a collection of this nursery has been requested. This is - * mutable as it is set by the store buffer, which otherwise cannot modify - * anything in the nursery. - */ + // Whether and why a collection of this nursery has been requested. This is + // mutable as it is set by the store buffer, which otherwise cannot modify + // anything in the nursery. mutable JS::GCReason minorGCTriggerReason_; - /* Profiling data. */ + // Profiling data. enum class ProfileKey { #define DEFINE_TIME_KEY(name, text) name, @@ -524,56 +491,46 @@ class Nursery { size_t tenuredCells = 0; } previousGC; - /* - * Calculate the promotion rate of the most recent minor GC. - * The valid_for_tenuring parameter is used to return whether this - * promotion rate is accurate enough (the nursery was full enough) to be - * used for tenuring and other decisions. - * - * Must only be called if the previousGC data is initialised. - */ + // Calculate the promotion rate of the most recent minor GC. + // The valid_for_tenuring parameter is used to return whether this + // promotion rate is accurate enough (the nursery was full enough) to be + // used for tenuring and other decisions. + // + // Must only be called if the previousGC data is initialised. float calcPromotionRate(bool* validForTenuring) const; - /* - * The set of externally malloced buffers potentially kept live by objects - * stored in the nursery. Any external buffers that do not belong to a - * tenured thing at the end of a minor GC must be freed. - */ + // The set of externally malloced buffers potentially kept live by objects + // stored in the nursery. Any external buffers that do not belong to a + // tenured thing at the end of a minor GC must be freed. BufferSet mallocedBuffers; - /* - * During a collection most hoisted slot and element buffers indicate their - * new location with a forwarding pointer at the base. This does not work - * for buffers whose length is less than pointer width, or when different - * buffers might overlap each other. For these, an entry in the following - * table is used. - */ + // During a collection most hoisted slot and element buffers indicate their + // new location with a forwarding pointer at the base. This does not work + // for buffers whose length is less than pointer width, or when different + // buffers might overlap each other. For these, an entry in the following + // table is used. typedef HashMap, SystemAllocPolicy> ForwardedBufferMap; ForwardedBufferMap forwardedBuffers; - /* - * When we assign a unique id to cell in the nursery, that almost always - * means that the cell will be in a hash table, and thus, held live, - * automatically moving the uid from the nursery to its new home in - * tenured. It is possible, if rare, for an object that acquired a uid to - * be dead before the next collection, in which case we need to know to - * remove it when we sweep. - * - * Note: we store the pointers as Cell* here, resulting in an ugly cast in - * sweep. This is because this structure is used to help implement - * stable object hashing and we have to break the cycle somehow. - */ + // When we assign a unique id to cell in the nursery, that almost always + // means that the cell will be in a hash table, and thus, held live, + // automatically moving the uid from the nursery to its new home in + // tenured. It is possible, if rare, for an object that acquired a uid to + // be dead before the next collection, in which case we need to know to + // remove it when we sweep. + // + // Note: we store the pointers as Cell* here, resulting in an ugly cast in + // sweep. This is because this structure is used to help implement + // stable object hashing and we have to break the cycle somehow. using CellsWithUniqueIdVector = Vector; CellsWithUniqueIdVector cellsWithUid_; using NativeObjectVector = Vector; NativeObjectVector dictionaryModeObjects_; - /* - * Lists of map and set objects allocated in the nursery or with iterators - * allocated there. Such objects need to be swept after minor GC. - */ + // Lists of map and set objects allocated in the nursery or with iterators + // allocated there. Such objects need to be swept after minor GC. Vector mapsWithNurseryMemory_; Vector setsWithNurseryMemory_; @@ -586,13 +543,11 @@ class Nursery { NurseryChunk& chunk(unsigned index) const { return *chunks_[index]; } - /* - * Set the current chunk. This updates the currentChunk_, position_ - * currentEnd_ and currentStringEnd_ values as approprite. It'll also - * poison the chunk, either a portion of the chunk if it is already the - * current chunk, or the whole chunk if fullPoison is true or it is not - * the current chunk. - */ + // Set the current chunk. This updates the currentChunk_, position_ + // currentEnd_ and currentStringEnd_ values as approprite. It'll also + // poison the chunk, either a portion of the chunk if it is already the + // current chunk, or the whole chunk if fullPoison is true or it is not + // the current chunk. void setCurrentChunk(unsigned chunkno); // extent is advisory, it will be ignored in sub-chunk and generational zeal @@ -602,10 +557,8 @@ class Nursery { void setCurrentEnd(); void setStartPosition(); - /* - * Allocate the next chunk, or the first chunk for initialization. - * Callers will probably want to call setCurrentChunk(0) next. - */ + // Allocate the next chunk, or the first chunk for initialization. + // Callers will probably want to call setCurrentChunk(0) next. MOZ_MUST_USE bool allocateNextChunk(unsigned chunkno, AutoLockGCBgAlloc& lock); @@ -620,7 +573,7 @@ class Nursery { const js::gc::GCSchedulingTunables& tunables() const; - /* Common internal allocator function. */ + // Common internal allocator function. void* allocate(size_t size); void doCollection(JS::GCReason reason, gc::TenureCountCache& tenureCounts); @@ -628,14 +581,12 @@ class Nursery { float doPretenuring(JSRuntime* rt, JS::GCReason reason, gc::TenureCountCache& tenureCounts); - /* - * Move the object at |src| in the Nursery to an already-allocated cell - * |dst| in Tenured. - */ + // Move the object at |src| in the Nursery to an already-allocated cell + // |dst| in Tenured. void collectToFixedPoint(TenuringTracer& trc, gc::TenureCountCache& tenureCounts); - /* Handle relocation of slots/elements pointers stored in Ion frames. */ + // Handle relocation of slots/elements pointers stored in Ion frames. inline void setForwardingPointer(void* oldData, void* newData, bool direct); inline void setDirectForwardingPointer(void* oldData, void* newData); @@ -647,22 +598,18 @@ class Nursery { ObjectElements* newHeader, uint32_t capacity); - /* - * Updates pointers to nursery objects that have been tenured and discards - * pointers to objects that have been freed. - */ + // Updates pointers to nursery objects that have been tenured and discards + // pointers to objects that have been freed. void sweep(JSTracer* trc); - /* - * Reset the current chunk and position after a minor collection. Also poison - * the nursery on debug & nightly builds. - */ + // Reset the current chunk and position after a minor collection. Also poison + // the nursery on debug & nightly builds. void clear(); void sweepDictionaryModeObjects(); void sweepMapAndSetObjects(); - /* Change the allocable space provided by the nursery. */ + // Change the allocable space provided by the nursery. void maybeResizeNursery(JS::GCReason reason); bool maybeResizeExact(JS::GCReason reason); size_t roundSize(size_t size) const; @@ -674,7 +621,7 @@ class Nursery { // vector. Shrinks the vector but does not update maxChunkCount(). void freeChunksFrom(unsigned firstFreeChunk); - /* Profile recording and printing. */ + // Profile recording and printing. void maybeClearProfileDurations(); void startProfile(ProfileKey key); void endProfile(ProfileKey key); @@ -686,6 +633,6 @@ class Nursery { friend struct NurseryChunk; }; -} /* namespace js */ +} // namespace js -#endif /* gc_Nursery_h */ +#endif // gc_Nursery_h diff --git a/js/src/jit/BaselineBailouts.cpp b/js/src/jit/BaselineBailouts.cpp index 2b200eb0a4d4..03c6cfbcbb01 100644 --- a/js/src/jit/BaselineBailouts.cpp +++ b/js/src/jit/BaselineBailouts.cpp @@ -2026,25 +2026,26 @@ bool jit::FinishBailoutToBaseline(BaselineBailoutInfo* bailoutInfo) { js_free(bailoutInfo); bailoutInfo = nullptr; - if (topFrame->environmentChain()) { - // Ensure the frame has a call object if it needs one. If the env chain - // is nullptr, we will enter baseline code at the prologue so no need to do - // anything in that case. - if (!EnsureHasEnvironmentObjects(cx, topFrame)) { - return false; - } + // If the frame has no environment chain, this must be a prologue bailout and + // we have to initialize with the function's initial environment to match + // emitInitFrameFields. + if (!topFrame->environmentChain()) { + topFrame->setEnvironmentChain(topFrame->callee()->environment()); + } - // If we bailed out before Ion could do the global declaration - // conflicts check, because we resume in the body instead of the - // prologue for global frames. - if (checkGlobalDeclarationConflicts) { - Rooted lexicalEnv( - cx, &cx->global()->lexicalEnvironment()); - RootedScript script(cx, topFrame->script()); - if (!CheckGlobalDeclarationConflicts(cx, script, lexicalEnv, - cx->global())) { - return false; - } + // Ensure the frame has a call object if it needs one. + if (!EnsureHasEnvironmentObjects(cx, topFrame)) { + return false; + } + + // Check for global declaration conflicts if necessary. + if (checkGlobalDeclarationConflicts) { + Rooted lexicalEnv( + cx, &cx->global()->lexicalEnvironment()); + RootedScript script(cx, topFrame->script()); + if (!CheckGlobalDeclarationConflicts(cx, script, lexicalEnv, + cx->global())) { + return false; } } @@ -2111,14 +2112,6 @@ bool jit::FinishBailoutToBaseline(BaselineBailoutInfo* bailoutInfo) { ++iter; } - // If the frame has no environment chain, this must be a prologue bailout and - // we have to initialize with the function's initial environment to match - // emitInitFrameFields. This has to happen last because the earlier bailout - // code uses |envChain == nullptr| to indicate a prologue bailout. - if (!topFrame->environmentChain()) { - topFrame->setEnvironmentChain(topFrame->callee()->environment()); - } - MOZ_ASSERT(innerScript); MOZ_ASSERT(outerScript); MOZ_ASSERT(outerFp); @@ -2162,6 +2155,14 @@ bool jit::FinishBailoutToBaseline(BaselineBailoutInfo* bailoutInfo) { UnwindEnvironment(cx, ei, tryPC); } + // Check for interrupts now because we might miss an interrupt check in JIT + // code when resuming in the prologue, after the stack/interrupt check. + if (!cx->isExceptionPending()) { + if (!CheckForInterrupt(cx)) { + return false; + } + } + JitSpew(JitSpew_BaselineBailouts, " Restored outerScript=(%s:%u:%u,%u) innerScript=(%s:%u:%u,%u) " "(bailoutKind=%u)", diff --git a/js/src/jit/BaselineCompiler.cpp b/js/src/jit/BaselineCompiler.cpp index d227d7ce1fb1..ae7121ade0a0 100644 --- a/js/src/jit/BaselineCompiler.cpp +++ b/js/src/jit/BaselineCompiler.cpp @@ -713,30 +713,16 @@ bool BaselineCodeGen::callVMInternal(VMFunctionId id, BaselineFrame::reverseOffsetOfFrameSize()); uint32_t frameBaseSize = BaselineFrame::FramePointerOffset + BaselineFrame::Size(); - if (phase == POST_INITIALIZE) { + if (phase == CallVMPhase::AfterPushingLocals) { storeFrameSizeAndPushDescriptor(frameBaseSize, argSize, frameSizeAddress, R0.scratchReg(), R1.scratchReg()); } else { - MOZ_ASSERT(phase == CHECK_OVER_RECURSED); - Label done, pushedFrameLocals; - - // If OVER_RECURSED is set, then frame locals haven't been pushed yet. - masm.branchTest32(Assembler::Zero, frame.addressOfFlags(), - Imm32(BaselineFrame::OVER_RECURSED), &pushedFrameLocals); - { - masm.store32(Imm32(frameBaseSize), frameSizeAddress); - uint32_t descriptor = - MakeFrameDescriptor(frameBaseSize + argSize, FrameType::BaselineJS, - ExitFrameLayout::Size()); - masm.push(Imm32(descriptor)); - masm.jump(&done); - } - masm.bind(&pushedFrameLocals); - { - storeFrameSizeAndPushDescriptor(frameBaseSize, argSize, frameSizeAddress, - R0.scratchReg(), R1.scratchReg()); - } - masm.bind(&done); + MOZ_ASSERT(phase == CallVMPhase::BeforePushingLocals); + masm.store32(Imm32(frameBaseSize), frameSizeAddress); + uint32_t descriptor = + MakeFrameDescriptor(frameBaseSize + argSize, FrameType::BaselineJS, + ExitFrameLayout::Size()); + masm.push(Imm32(descriptor)); } MOZ_ASSERT(fun.expectTailCall == NonTailCall); // Perform the call. @@ -773,36 +759,26 @@ bool BaselineCodeGen::callVM(CallVMPhase phase) { template bool BaselineCodeGen::emitStackCheck() { - // If this is the late stack check for a frame which contains an early stack - // check, then the early stack check might have failed and skipped past the - // pushing of locals on the stack. - // - // If this is a possibility, then the OVER_RECURSED flag should be checked, - // and the VMCall to CheckOverRecursedBaseline done unconditionally if it's - // set. - Label forceCall; - if (handler.needsEarlyStackCheck()) { - masm.branchTest32(Assembler::NonZero, frame.addressOfFlags(), - Imm32(BaselineFrame::OVER_RECURSED), &forceCall); - } - Label skipCall; - masm.branchStackPtrRhs(Assembler::BelowOrEqual, - AbsoluteAddress(cx->addressOfJitStackLimit()), - &skipCall); - - if (handler.needsEarlyStackCheck()) { - masm.bind(&forceCall); + if (handler.mustIncludeSlotsInStackCheck()) { + // Subtract the size of script->nslots() first. + Register scratch = R1.scratchReg(); + masm.moveStackPtrTo(scratch); + subtractScriptSlotsSize(scratch, R2.scratchReg()); + masm.branchPtr(Assembler::BelowOrEqual, + AbsoluteAddress(cx->addressOfJitStackLimit()), scratch, + &skipCall); + } else { + masm.branchStackPtrRhs(Assembler::BelowOrEqual, + AbsoluteAddress(cx->addressOfJitStackLimit()), + &skipCall); } prepareVMCall(); masm.loadBaselineFramePtr(BaselineFrameReg, R1.scratchReg()); pushArg(R1.scratchReg()); - CallVMPhase phase = POST_INITIALIZE; - if (handler.needsEarlyStackCheck()) { - phase = CHECK_OVER_RECURSED; - } + const CallVMPhase phase = CallVMPhase::BeforePushingLocals; using Fn = bool (*)(JSContext*, BaselineFrame*); if (!callVMNonOp(phase)) { @@ -1287,19 +1263,16 @@ bool BaselineInterpreterCodeGen::initEnvironmentChainHelper( template bool BaselineCodeGen::initEnvironmentChain() { - CallVMPhase phase = POST_INITIALIZE; - if (handler.needsEarlyStackCheck()) { - phase = CHECK_OVER_RECURSED; - } - - auto initFunctionEnv = [this, phase]() { - auto initEnv = [this, phase]() { + auto initFunctionEnv = [this]() { + auto initEnv = [this]() { // Call into the VM to create the proper environment objects. prepareVMCall(); masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg()); pushArg(R0.scratchReg()); + const CallVMPhase phase = CallVMPhase::BeforePushingLocals; + using Fn = bool (*)(JSContext*, BaselineFrame*); return callVMNonOp(phase); }; @@ -1308,7 +1281,7 @@ bool BaselineCodeGen::initEnvironmentChain() { initEnv, R2.scratchReg()); }; - auto initGlobalOrEvalEnv = [this, phase]() { + auto initGlobalOrEvalEnv = [this]() { // EnvironmentChain pointer in BaselineFrame has already been initialized // in prologue, but we need to check for redeclaration errors in global and // eval scripts. @@ -1319,6 +1292,8 @@ bool BaselineCodeGen::initEnvironmentChain() { masm.loadPtr(frame.addressOfEnvironmentChain(), R0.scratchReg()); pushArg(R0.scratchReg()); + const CallVMPhase phase = CallVMPhase::BeforePushingLocals; + using Fn = bool (*)(JSContext*, HandleObject, HandleScript); return callVMNonOp(phase); }; @@ -6719,79 +6694,40 @@ bool BaselineCodeGen::emitPrologue() { return false; } - // Functions with a large number of locals require two stack checks. - // The VMCall for a fallible stack check can only occur after the - // env chain has been initialized, as that is required for proper - // exception handling if the VMCall returns false. The env chain - // initialization can only happen after the UndefinedValues for the - // local slots have been pushed. However by that time, the stack might - // have grown too much. - // - // In these cases, we emit an extra, early, infallible check before pushing - // the locals. The early check just sets a flag on the frame if the stack - // check fails. If the flag is set, then the jitcode skips past the pushing - // of the locals, and directly to env chain initialization followed by the - // actual stack check, which will throw the correct exception. - Label earlyStackCheckFailed; - if (handler.needsEarlyStackCheck()) { - // Subtract the size of script->nslots() from the stack pointer. - Register scratch = R1.scratchReg(); - masm.moveStackPtrTo(scratch); - subtractScriptSlotsSize(scratch, R2.scratchReg()); + // When compiling with Debugger instrumentation, set the debuggeeness of + // the frame before any operation that can call into the VM. + if (!emitIsDebuggeeCheck()) { + return false; + } - // Set the OVER_RECURSED flag on the frame if the computed stack pointer - // overflows the stack limit. We have to use the actual (*NoInterrupt) - // stack limit here because we don't want to set the flag and throw an - // overrecursion exception later in the interrupt case. - Label stackCheckOk; - masm.branchPtr(Assembler::BelowOrEqual, - AbsoluteAddress(cx->addressOfJitStackLimitNoInterrupt()), - scratch, &stackCheckOk); - { - masm.or32(Imm32(BaselineFrame::OVER_RECURSED), frame.addressOfFlags()); - masm.jump(&earlyStackCheckFailed); - } - masm.bind(&stackCheckOk); + // Initialize the env chain before any operation that may call into the VM and + // trigger a GC. + if (!initEnvironmentChain()) { + return false; + } + + // Check for overrecursion before initializing locals. + if (!emitStackCheck()) { + return false; } emitInitializeLocals(); - if (handler.needsEarlyStackCheck()) { - masm.bind(&earlyStackCheckFailed); - } - #ifdef JS_TRACE_LOGGING if (JS::TraceLoggerSupported() && !emitTraceLoggerEnter()) { return false; } #endif - // Record the offset of the prologue, because Ion can bailout before - // the env chain is initialized. + // Record prologue offset for Ion bailouts. bailoutPrologueOffset_ = CodeOffset(masm.currentOffset()); - // When compiling with Debugger instrumentation, set the debuggeeness of - // the frame before any operation that can call into the VM. - if (!emitIsDebuggeeCheck()) { - return false; - } - - // Initialize the env chain before any operation that may - // call into the VM and trigger a GC. - if (!initEnvironmentChain()) { - return false; - } - frame.assertSyncedStack(); if (JSScript* script = handler.maybeScript()) { masm.debugAssertContextRealm(script->realm(), R1.scratchReg()); } - if (!emitStackCheck()) { - return false; - } - if (!emitDebugPrologue()) { return false; } diff --git a/js/src/jit/BaselineCompiler.h b/js/src/jit/BaselineCompiler.h index 0144da1abc2a..b3a575b7e246 100644 --- a/js/src/jit/BaselineCompiler.h +++ b/js/src/jit/BaselineCompiler.h @@ -363,14 +363,14 @@ class BaselineCodeGen { const Address& frameSizeAddr, Register scratch1, Register scratch2); - enum CallVMPhase { POST_INITIALIZE, CHECK_OVER_RECURSED }; + enum class CallVMPhase { BeforePushingLocals, AfterPushingLocals }; bool callVMInternal(VMFunctionId id, CallVMPhase phase); template - bool callVM(CallVMPhase phase = POST_INITIALIZE); + bool callVM(CallVMPhase phase = CallVMPhase::AfterPushingLocals); template - bool callVMNonOp(CallVMPhase phase = POST_INITIALIZE) { + bool callVMNonOp(CallVMPhase phase = CallVMPhase::AfterPushingLocals) { if (!callVM(phase)) { return false; } @@ -597,11 +597,11 @@ class BaselineCompilerHandler { retAddrEntries_.back().setKind(kind); } - // If a script has more |nslots| than this, then emit code to do an - // early stack check. - bool needsEarlyStackCheck() const { - static const unsigned EARLY_STACK_CHECK_SLOT_COUNT = 128; - return script()->nslots() > EARLY_STACK_CHECK_SLOT_COUNT; + // If a script has more |nslots| than this the stack check must account + // for these slots explicitly. + bool mustIncludeSlotsInStackCheck() const { + static constexpr size_t NumSlotsLimit = 128; + return script()->nslots() > NumSlotsLimit; } JSObject* maybeNoCloneSingletonObject(); @@ -725,9 +725,9 @@ class BaselineInterpreterHandler { bool maybeIonCompileable() const { return true; } - // The interpreter always does the early stack check because we don't know the - // frame size statically. - bool needsEarlyStackCheck() const { return true; } + // The interpreter doesn't know the number of slots statically so we always + // include them. + bool mustIncludeSlotsInStackCheck() const { return true; } JSObject* maybeNoCloneSingletonObject() { return nullptr; } }; diff --git a/js/src/jit/BaselineFrame.h b/js/src/jit/BaselineFrame.h index 5f3c9fa04426..cd0cc72d8ac7 100644 --- a/js/src/jit/BaselineFrame.h +++ b/js/src/jit/BaselineFrame.h @@ -51,14 +51,9 @@ class BaselineFrame { // of invariants of debuggee compartments, scripts, and frames. DEBUGGEE = 1 << 6, - // (1 << 7 and 1 << 8 are unused) - - // Frame has over-recursed on an early check. - OVER_RECURSED = 1 << 9, - // Frame has a BaselineRecompileInfo stashed in the scratch value // slot. See PatchBaselineFramesForDebugMode. - HAS_DEBUG_MODE_OSR_INFO = 1 << 10, + HAS_DEBUG_MODE_OSR_INFO = 1 << 7, // This flag is intended for use whenever the frame is settled on a // native code address without a corresponding RetAddrEntry. In this @@ -72,12 +67,12 @@ class BaselineFrame { // This flag should never be set on the top frame while we're // executing JIT code. In debug builds, it is checked before and // after VM calls. - HAS_OVERRIDE_PC = 1 << 11, + HAS_OVERRIDE_PC = 1 << 8, // If set, we're handling an exception for this frame. This is set for // debug mode OSR sanity checking when it handles corner cases which // only arise during exception handling. - HANDLING_EXCEPTION = 1 << 12, + HANDLING_EXCEPTION = 1 << 9, }; protected: // Silence Clang warning about unused private fields. @@ -315,10 +310,6 @@ class BaselineFrame { void setIsHandlingException() { flags_ |= HANDLING_EXCEPTION; } void unsetIsHandlingException() { flags_ &= ~HANDLING_EXCEPTION; } - bool overRecursed() const { return flags_ & OVER_RECURSED; } - - void setOverRecursed() { flags_ |= OVER_RECURSED; } - BaselineDebugModeOSRInfo* debugModeOSRInfo() { MOZ_ASSERT(flags_ & HAS_DEBUG_MODE_OSR_INFO); return debugModeOSRInfo_; diff --git a/js/src/jit/VMFunctions.cpp b/js/src/jit/VMFunctions.cpp index d6090a2099b1..cff07369239d 100644 --- a/js/src/jit/VMFunctions.cpp +++ b/js/src/jit/VMFunctions.cpp @@ -297,7 +297,7 @@ bool InvokeFromInterpreterStub(JSContext* cx, return true; } -bool CheckOverRecursed(JSContext* cx) { +static bool CheckOverRecursedImpl(JSContext* cx, size_t extra) { // We just failed the jitStackLimit check. There are two possible reasons: // 1) jitStackLimit was the real stack limit and we're over-recursed // 2) jitStackLimit was set to UINTPTR_MAX by JSContext::requestInterrupt @@ -305,12 +305,12 @@ bool CheckOverRecursed(JSContext* cx) { // This handles 1). #ifdef JS_SIMULATOR - if (cx->simulator()->overRecursedWithExtra(0)) { + if (cx->simulator()->overRecursedWithExtra(extra)) { ReportOverRecursed(cx); return false; } #else - if (!CheckRecursionLimit(cx)) { + if (!CheckRecursionLimitWithExtra(cx, extra)) { return false; } #endif @@ -320,19 +320,13 @@ bool CheckOverRecursed(JSContext* cx) { return cx->handleInterrupt(); } -// This function gets called when the overrecursion check fails for a Baseline -// frame. This is just like CheckOverRecursed, with an extra check to handle -// early stack check failures. -bool CheckOverRecursedBaseline(JSContext* cx, BaselineFrame* frame) { - // The OVERRECURSED flag may have already been set on the frame by an - // early over-recursed check (before pushing the locals). If so, throw - // immediately. - if (frame->overRecursed()) { - ReportOverRecursed(cx); - return false; - } +bool CheckOverRecursed(JSContext* cx) { return CheckOverRecursedImpl(cx, 0); } - return CheckOverRecursed(cx); +bool CheckOverRecursedBaseline(JSContext* cx, BaselineFrame* frame) { + // The stack check in Baseline happens before pushing locals so we have to + // account for that by including script->nslots() in the C++ recursion check. + size_t extra = frame->script()->nslots() * sizeof(Value); + return CheckOverRecursedImpl(cx, extra); } bool MutatePrototype(JSContext* cx, HandlePlainObject obj, HandleValue value) { diff --git a/js/src/jsfriendapi.h b/js/src/jsfriendapi.h index b07201e132e2..4e88fb07f8de 100644 --- a/js/src/jsfriendapi.h +++ b/js/src/jsfriendapi.h @@ -1059,6 +1059,18 @@ MOZ_ALWAYS_INLINE bool CheckRecursionLimitWithStackPointer(JSContext* cx, return true; } +MOZ_ALWAYS_INLINE bool CheckRecursionLimitWithExtra(JSContext* cx, + size_t extra) { + char stackDummy; + char* sp = &stackDummy; +#if JS_STACK_GROWTH_DIRECTION > 0 + sp += extra; +#else + sp -= extra; +#endif + return CheckRecursionLimitWithStackPointer(cx, sp); +} + MOZ_ALWAYS_INLINE bool CheckSystemRecursionLimit(JSContext* cx) { return CheckRecursionLimit(cx, GetNativeStackLimit(cx, JS::StackForSystemCode)); diff --git a/js/src/vm/JSScript.cpp b/js/src/vm/JSScript.cpp index 9c71d21a9124..9f033895ed34 100644 --- a/js/src/vm/JSScript.cpp +++ b/js/src/vm/JSScript.cpp @@ -267,8 +267,7 @@ static XDRResult XDRRelazificationInfo(XDRState* xdr, HandleFunction fun, HandleScript script, HandleScope enclosingScope, MutableHandle lazy) { - MOZ_ASSERT_IF(mode == XDR_ENCODE, script->isRelazifiableIgnoringJitCode() && - script->maybeLazyScript()); + MOZ_ASSERT_IF(mode == XDR_ENCODE, script->maybeLazyScript()); MOZ_ASSERT_IF(mode == XDR_ENCODE, !lazy->numInnerFunctions()); JSContext* cx = xdr->cx(); @@ -1025,7 +1024,7 @@ XDRResult js::XDRScript(XDRState* xdr, HandleScope scriptEnclosingScope, if (!sourceObjectArg) { xdrScriptFlags |= (1 << OwnSource); } - if (script->isRelazifiableIgnoringJitCode()) { + if (script->maybeLazyScript()) { xdrScriptFlags |= (1 << HasLazyScript); } } diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp index 2221f477d35e..a9d82a00947f 100644 --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -7497,6 +7497,7 @@ nsLayoutUtils::SurfaceFromOffscreenCanvas(OffscreenCanvas* aOffscreenCanvas, result.mHasSize = true; result.mSize = size; + result.mIntrinsicSize = size; result.mIsWriteOnly = aOffscreenCanvas->IsWriteOnly(); return result; @@ -7577,6 +7578,7 @@ nsLayoutUtils::SurfaceFromElementResult nsLayoutUtils::SurfaceFromElement( if (NS_FAILED(rv) || NS_FAILED(rv2)) return result; } result.mSize = IntSize(imgWidth, imgHeight); + result.mIntrinsicSize = IntSize(imgWidth, imgHeight); if (!noRasterize || imgContainer->GetType() == imgIContainer::TYPE_RASTER) { if (aSurfaceFlags & SFE_WANT_IMAGE_SURFACE) { @@ -7674,6 +7676,7 @@ nsLayoutUtils::SurfaceFromElementResult nsLayoutUtils::SurfaceFromElement( result.mHasSize = true; result.mSize = size; + result.mIntrinsicSize = size; result.mPrincipal = aElement->NodePrincipal(); result.mHadCrossOriginRedirects = false; result.mIsWriteOnly = aElement->IsWriteOnly(); @@ -7721,6 +7724,8 @@ nsLayoutUtils::SurfaceFromElementResult nsLayoutUtils::SurfaceFromElement( result.mCORSUsed = aElement->GetCORSMode() != CORS_NONE; result.mHasSize = true; result.mSize = result.mLayersImage->GetSize(); + result.mIntrinsicSize = + gfx::IntSize(aElement->VideoWidth(), aElement->VideoHeight()); result.mPrincipal = principal.forget(); result.mHadCrossOriginRedirects = aElement->HadCrossOriginRedirects(); result.mIsWriteOnly = CanvasUtils::CheckWriteOnlySecurity( diff --git a/layout/base/nsLayoutUtils.h b/layout/base/nsLayoutUtils.h index 6c21a2f85e20..9b8fe9f9271d 100644 --- a/layout/base/nsLayoutUtils.h +++ b/layout/base/nsLayoutUtils.h @@ -2155,6 +2155,8 @@ class nsLayoutUtils { /* The size of the surface */ mozilla::gfx::IntSize mSize; + /* The size the surface is intended to be rendered at */ + mozilla::gfx::IntSize mIntrinsicSize; /* The principal associated with the element whose surface was returned. If there is a surface, this will never be null. */ nsCOMPtr mPrincipal; diff --git a/layout/generic/nsPageSequenceFrame.h b/layout/generic/nsPageSequenceFrame.h index 5dbb93497e95..90781307c552 100644 --- a/layout/generic/nsPageSequenceFrame.h +++ b/layout/generic/nsPageSequenceFrame.h @@ -7,7 +7,6 @@ #define nsPageSequenceFrame_h___ #include "mozilla/Attributes.h" -#include "nsPageSequenceFrame.h" #include "nsContainerFrame.h" #include "nsIPrintSettings.h" diff --git a/layout/reftests/forms/input/file/button-height-ref.html b/layout/reftests/forms/input/file/button-height-ref.html new file mode 100644 index 000000000000..a80d261cf81d --- /dev/null +++ b/layout/reftests/forms/input/file/button-height-ref.html @@ -0,0 +1,6 @@ + + + diff --git a/layout/reftests/forms/input/file/button-height.html b/layout/reftests/forms/input/file/button-height.html new file mode 100644 index 000000000000..b1094ad783f3 --- /dev/null +++ b/layout/reftests/forms/input/file/button-height.html @@ -0,0 +1,6 @@ + + + diff --git a/layout/reftests/forms/input/file/reftest.list b/layout/reftests/forms/input/file/reftest.list index a7a80ef6a181..58a42489c85c 100644 --- a/layout/reftests/forms/input/file/reftest.list +++ b/layout/reftests/forms/input/file/reftest.list @@ -9,3 +9,4 @@ fuzzy-if(Android,0-2,0-2) fuzzy-if(OSX,0-34,0-134) fails-if(webrender&&!(cocoaWi == label-min-inline-size.html label-min-inline-size-ref.html == css-overflow.html css-overflow-ref.html == css-display.html css-display-ref.html +== button-height.html button-height-ref.html diff --git a/layout/style/res/forms.css b/layout/style/res/forms.css index 5c61a3381253..0c2b50cc2cb9 100644 --- a/layout/style/res/forms.css +++ b/layout/style/res/forms.css @@ -504,7 +504,6 @@ input[type="file"] > label { /* button part of file selector */ input[type="file"] > button { - block-size: inherit; font-size: unset; letter-spacing: unset; cursor: unset; diff --git a/layout/tools/reftest/runreftest.py b/layout/tools/reftest/runreftest.py index 50b0b45436f6..00ae0b6e53ae 100644 --- a/layout/tools/reftest/runreftest.py +++ b/layout/tools/reftest/runreftest.py @@ -765,7 +765,7 @@ class RefTest(object): 'processOutputLine': [self.outputHandler], } - if mozinfo.isWin: + if mozinfo.isWin or mozinfo.isMac: # Prevents log interleaving on Windows at the expense of losing # true log order. See bug 798300 and bug 1324961 for more details. kp_kwargs['processStderrLine'] = [self.outputHandler] diff --git a/mobile/android/app/src/main/res/values/dimens.xml b/mobile/android/app/src/main/res/values/dimens.xml index ed1f2ed67756..3532cad7b0d9 100644 --- a/mobile/android/app/src/main/res/values/dimens.xml +++ b/mobile/android/app/src/main/res/values/dimens.xml @@ -150,6 +150,10 @@ 64dip 240dp 256dp + + 16dp + 18dp + 14sp 1dp 32dp 36dp diff --git a/mobile/android/base/java/org/mozilla/gecko/text/FloatingActionModeCallback.java b/mobile/android/base/java/org/mozilla/gecko/text/FloatingActionModeCallback.java index 46eb18f1776e..d090e49e31f6 100644 --- a/mobile/android/base/java/org/mozilla/gecko/text/FloatingActionModeCallback.java +++ b/mobile/android/base/java/org/mozilla/gecko/text/FloatingActionModeCallback.java @@ -5,15 +5,22 @@ package org.mozilla.gecko.text; import android.annotation.TargetApi; +import android.content.Context; +import android.content.res.Resources; import android.graphics.Rect; +import android.graphics.Typeface; import android.os.Build; +import android.support.annotation.NonNull; +import android.text.TextPaint; import android.view.ActionMode; import android.view.Menu; import android.view.MenuItem; import android.view.View; -import org.mozilla.gecko.GeckoApp; +import org.mozilla.gecko.GeckoAppShell; +import org.mozilla.gecko.R; import org.mozilla.gecko.util.GeckoBundle; +import org.mozilla.gecko.util.WindowUtils; import org.mozilla.geckoview.GeckoViewBridge; import java.util.List; @@ -43,7 +50,8 @@ public class FloatingActionModeCallback extends ActionMode.Callback2 { for (int i = 0; i < actions.size(); i++) { final TextAction action = actions.get(i); - menu.add(Menu.NONE, i, action.getFloatingOrder(), action.getLabel()); + final String actionLabel = getOneLinerMenuText(action.getLabel()); + menu.add(Menu.NONE, i, action.getFloatingOrder(), actionLabel); } return true; @@ -70,4 +78,38 @@ public class FloatingActionModeCallback extends ActionMode.Callback2 { outRect.set(contentRect); } } + + // There's currently a bug in Android's framework that manifests by placing the floating menu + // off-screen if a menu label overflows the menu's width. + // https://issuetracker.google.com/issues/137169336 + // To overcome this we'll manually check and truncate any menu label that could cause issues. + private static @NonNull String getOneLinerMenuText(@NonNull final String text) { + final int textLength = text.length(); + + // Avoid heavy unneeded calculations if the text is small + if (textLength < 30) { + return text; + } + + // Simulate as best as possible the floating menu button style used in Android framework + // https://android.googlesource.com/platform/frameworks/base/+/eb101a7/core/java/com/android/internal/widget/FloatingToolbar.java + final Context context = GeckoAppShell.getApplicationContext(); + final Resources resources = context.getResources(); + final TextPaint textPaint = new TextPaint(); + textPaint.setTextSize(resources.getDimensionPixelSize(R.dimen.floating_toolbar_text_size)); + textPaint.setTypeface(Typeface.create("sans-serif-medium", Typeface.NORMAL)); + final int screenWidth = WindowUtils.getScreenWidth(context); + final int menuWidth = screenWidth + - (2 * resources.getDimensionPixelSize(R.dimen.floating_toolbar_horizontal_margin)) + - (2 * resources.getDimensionPixelSize(R.dimen.floating_toolbar_menu_button_side_padding)); + + // If the text cannot fit on one line ellipsize it manually + final int charactersThatFit = textPaint.breakText(text, 0, textLength, true, menuWidth, null); + final boolean shouldEllipsize = textLength > charactersThatFit; + if (shouldEllipsize) { + return text.substring(0, charactersThatFit - 3) + "..."; + } else { + return text; + } + } } diff --git a/mobile/android/base/java/org/mozilla/gecko/util/WindowUtils.java b/mobile/android/base/java/org/mozilla/gecko/util/WindowUtils.java index 4779e1c467df..ff518dd52c30 100644 --- a/mobile/android/base/java/org/mozilla/gecko/util/WindowUtils.java +++ b/mobile/android/base/java/org/mozilla/gecko/util/WindowUtils.java @@ -7,6 +7,7 @@ package org.mozilla.gecko.util; import android.content.Context; import android.os.Build; +import android.support.annotation.NonNull; import android.util.DisplayMetrics; import android.util.Log; import android.view.Display; @@ -52,7 +53,28 @@ public class WindowUtils { } return Math.max(tempWidth, tempHeight); + } + } + public static int getScreenWidth(@NonNull final Context context) { + final Display display = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay(); + + if (Build.VERSION.SDK_INT >= 17) { + final DisplayMetrics realMetrics = new DisplayMetrics(); + display.getRealMetrics(realMetrics); + return realMetrics.widthPixels; + } else { + int tempWidth; + try { + final Method getRawW = Display.class.getMethod("getRawWidth"); + tempWidth = (Integer) getRawW.invoke(display); + } catch (Exception e) { + // This is the best we can do. + tempWidth = display.getWidth(); + Log.w(LOGTAG, "Couldn't use reflection to get the real display metrics."); + } + + return tempWidth; } } } diff --git a/modules/libpref/init/StaticPrefList.h b/modules/libpref/init/StaticPrefList.h index 5b1cdc4ee2e2..6a1b859ff908 100644 --- a/modules/libpref/init/StaticPrefList.h +++ b/modules/libpref/init/StaticPrefList.h @@ -2779,26 +2779,18 @@ VARCACHE_PREF( bool, false ) -// Is support for Navigator.geolocation enabled? -VARCACHE_PREF( - Live, - "geo.enabled", - geo_enabled, - bool, true -) - // WebIDL test prefs VARCACHE_PREF( Live, - "abc.def", - abc_def, + "dom.webidl.test1", + dom_webidl_test1, bool, true ) VARCACHE_PREF( Live, - "ghi.jkl", - ghi_jkl, + "dom.webidl.test2", + dom_webidl_test2, bool, true ) @@ -3062,6 +3054,18 @@ VARCACHE_PREF( RelaxedAtomicInt32, 1000 ) +//--------------------------------------------------------------------------- +// Prefs starting with "geo." +//--------------------------------------------------------------------------- + +// Is support for Navigator.geolocation enabled? +VARCACHE_PREF( + Live, + "geo.enabled", + geo_enabled, + bool, true +) + //--------------------------------------------------------------------------- // Prefs starting with "gfx." //--------------------------------------------------------------------------- diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 6843428dcaf2..3493a7f1e8ca 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -2131,6 +2131,9 @@ pref("network.http.tailing.total-max", 45000); // Enable or disable the whole fix from bug 1563538 pref("network.http.spdy.bug1563538", true); +pref("network.http.spdy.bug1563695", true); +pref("network.http.spdy.bug1562315", true); +pref("network.http.spdy.bug1556491", true); pref("permissions.default.image", 1); // 1-Accept, 2-Deny, 3-dontAcceptForeign @@ -2463,7 +2466,7 @@ pref("security.dialog_enable_delay", 1000); pref("security.notification_enable_delay", 500); #if defined(DEBUG) && !defined(ANDROID) -pref("csp.about_uris_without_csp", "blank,printpreview,srcdoc,addons,config,debugging,downloads,home,newtab,plugins,preferences,sessionrestore,sync-log,welcomeback"); +pref("csp.about_uris_without_csp", "blank,printpreview,srcdoc,addons,config,debugging,downloads,home,newtab,preferences,sessionrestore,sync-log,welcomeback"); // the following prefs are for testing purposes only. pref("csp.overrule_about_uris_without_csp_whitelist", false); pref("csp.skip_about_page_has_csp_assert", false); diff --git a/netwerk/base/SimpleChannelParent.cpp b/netwerk/base/SimpleChannelParent.cpp index a276b728ace8..ecdb2edc33c4 100644 --- a/netwerk/base/SimpleChannelParent.cpp +++ b/netwerk/base/SimpleChannelParent.cpp @@ -23,7 +23,7 @@ bool SimpleChannelParent::Init(const uint32_t& channelId) { } NS_IMETHODIMP -SimpleChannelParent::SetParentListener(HttpChannelParentListener* aListener) { +SimpleChannelParent::SetParentListener(ParentChannelListener* aListener) { // Nothing to do. return NS_OK; } diff --git a/netwerk/base/nsIParentChannel.idl b/netwerk/base/nsIParentChannel.idl index 197016755883..e5afceeb1244 100644 --- a/netwerk/base/nsIParentChannel.idl +++ b/netwerk/base/nsIParentChannel.idl @@ -10,12 +10,12 @@ interface nsIRemoteTab; %{C++ namespace mozilla { namespace net { -class HttpChannelParentListener; +class ParentChannelListener; } } %} -[ptr] native HttpChannelParentListener(mozilla::net::HttpChannelParentListener); +[ptr] native ParentChannelListener(mozilla::net::ParentChannelListener); /** * Implemented by chrome side of IPC protocols. @@ -25,9 +25,9 @@ class HttpChannelParentListener; interface nsIParentChannel : nsIStreamListener { /** - * Called to set the HttpChannelParentListener object (optional). + * Called to set the ParentChannelListener object (optional). */ - [noscript] void setParentListener(in HttpChannelParentListener listener); + [noscript] void setParentListener(in ParentChannelListener listener); /** * Called to notify the HttpChannelChild that channel classifier protection diff --git a/netwerk/base/nsIParentRedirectingChannel.idl b/netwerk/base/nsIParentRedirectingChannel.idl index d0505f70c753..b2fe8c83d2c9 100644 --- a/netwerk/base/nsIParentRedirectingChannel.idl +++ b/netwerk/base/nsIParentRedirectingChannel.idl @@ -34,16 +34,13 @@ interface nsIParentRedirectingChannel : nsIParentChannel * URI. The implementation is responsible for calling the redirect observers * on the child process and provide the decision result to the callback. * - * @param newChannelId - * id of the redirect channel obtained from nsIRedirectChannelRegistrar. * @param newURI * the URI we redirect to * @param callback * redirect result callback, usage is compatible with how * nsIChannelEventSink defines it */ - void startRedirect(in uint32_t newChannelId, - in nsIChannel newChannel, + void startRedirect(in nsIChannel newChannel, in uint32_t redirectFlags, in nsIAsyncVerifyRedirectCallback callback); @@ -64,8 +61,8 @@ interface nsIParentRedirectingChannel : nsIParentChannel * that moment the nsIParentChannel implementation expects it will be * forwarded all notifications from the 'real' channel. * - * Primarilly used by HttpChannelParentListener::OnRedirectResult and kept - * as mActiveChannel and mRedirectChannel in that class. + * Primarilly used by ParentChannelListener::OnRedirectResult and kept as + * mActiveChannel and mRedirectChannel in that class. */ void completeRedirect(in boolean succeeded); }; diff --git a/netwerk/base/nsIRedirectChannelRegistrar.idl b/netwerk/base/nsIRedirectChannelRegistrar.idl index c5cce0b1ca1e..be1733f4e171 100644 --- a/netwerk/base/nsIRedirectChannelRegistrar.idl +++ b/netwerk/base/nsIRedirectChannelRegistrar.idl @@ -22,7 +22,7 @@ interface nsIRedirectChannelRegistrar : nsISupports * Register the redirect target channel and obtain a unique ID for that * channel. * - * Primarily used in HttpChannelParentListener::AsyncOnChannelRedirect to get + * Primarily used in ParentChannelListener::AsyncOnChannelRedirect to get * a channel id sent to the HttpChannelChild being redirected. */ uint32_t registerChannel(in nsIChannel channel); @@ -54,7 +54,7 @@ interface nsIRedirectChannelRegistrar : nsISupports * channel, all notification from the redirect target channel will be * forwarded to this stream listener. * - * Primarilly used in HttpChannelParentListener::OnRedirectResult callback + * Primarilly used in ParentChannelListener::OnRedirectResult callback * to grab the created parent side of the channel and forward notifications * to it. */ @@ -66,7 +66,7 @@ interface nsIRedirectChannelRegistrar : nsISupports * self. This releases both the real and parent channel registered under * the id. * - * Primarilly used in HttpChannelParentListener::OnRedirectResult callback. + * Primarilly used in ParentChannelListener::OnRedirectResult callback. */ void deregisterChannels(in uint32_t id); }; diff --git a/netwerk/ipc/SocketProcessBridgeChild.cpp b/netwerk/ipc/SocketProcessBridgeChild.cpp index d1dbaa6f22f9..af1f6a229538 100644 --- a/netwerk/ipc/SocketProcessBridgeChild.cpp +++ b/netwerk/ipc/SocketProcessBridgeChild.cpp @@ -6,6 +6,7 @@ #include "SocketProcessBridgeChild.h" #include "SocketProcessLogging.h" +#include "mozilla/dom/ContentChild.h" #include "mozilla/net/NeckoChild.h" #include "nsIObserverService.h" #include "nsThreadUtils.h" @@ -13,6 +14,9 @@ #include "mozilla/Preferences.h" namespace mozilla { + +using dom::ContentChild; + namespace net { StaticRefPtr @@ -77,10 +81,20 @@ SocketProcessBridgeChild::GetSocketProcessBridge() { return GetPromise::CreateAndResolve(sSocketProcessBridgeChild, __func__); } + ContentChild* content = ContentChild::GetSingleton(); + if (!content || content->IsShuttingDown()) { + return nullptr; + } + return gNeckoChild->SendInitSocketProcessBridge()->Then( GetMainThreadSerialEventTarget(), __func__, [](NeckoChild::InitSocketProcessBridgePromise::ResolveOrRejectValue&& aResult) { + ContentChild* content = ContentChild::GetSingleton(); + if (!content || content->IsShuttingDown()) { + return GetPromise::CreateAndReject( + nsCString("ContentChild is shutting down."), __func__); + } if (!sSocketProcessBridgeChild) { if (aResult.IsReject()) { return GetPromise::CreateAndReject( diff --git a/netwerk/protocol/data/DataChannelParent.cpp b/netwerk/protocol/data/DataChannelParent.cpp index 4eabe5edaaa1..cdc7bd70fa9d 100644 --- a/netwerk/protocol/data/DataChannelParent.cpp +++ b/netwerk/protocol/data/DataChannelParent.cpp @@ -23,7 +23,7 @@ bool DataChannelParent::Init(const uint32_t& channelId) { } NS_IMETHODIMP -DataChannelParent::SetParentListener(HttpChannelParentListener* aListener) { +DataChannelParent::SetParentListener(ParentChannelListener* aListener) { // Nothing to do. return NS_OK; } diff --git a/netwerk/protocol/file/FileChannelParent.cpp b/netwerk/protocol/file/FileChannelParent.cpp index d01afecc5c38..747c7b4fc8f3 100644 --- a/netwerk/protocol/file/FileChannelParent.cpp +++ b/netwerk/protocol/file/FileChannelParent.cpp @@ -23,7 +23,7 @@ bool FileChannelParent::Init(const uint32_t& channelId) { } NS_IMETHODIMP -FileChannelParent::SetParentListener(HttpChannelParentListener* aListener) { +FileChannelParent::SetParentListener(ParentChannelListener* aListener) { // Nothing to do. return NS_OK; } diff --git a/netwerk/protocol/ftp/FTPChannelParent.cpp b/netwerk/protocol/ftp/FTPChannelParent.cpp index 4f261c040d3d..6eaa227a06b5 100644 --- a/netwerk/protocol/ftp/FTPChannelParent.cpp +++ b/netwerk/protocol/ftp/FTPChannelParent.cpp @@ -490,8 +490,8 @@ FTPChannelParent::OnDataAvailable(nsIRequest* aRequest, //----------------------------------------------------------------------------- NS_IMETHODIMP -FTPChannelParent::SetParentListener(HttpChannelParentListener* aListener) { - // Do not need ptr to HttpChannelParentListener. +FTPChannelParent::SetParentListener(ParentChannelListener* aListener) { + // Do not need ptr to ParentChannelListener. return NS_OK; } diff --git a/netwerk/protocol/http/HttpChannelParent.cpp b/netwerk/protocol/http/HttpChannelParent.cpp index fdbab0e4d639..b6ad7ce68722 100644 --- a/netwerk/protocol/http/HttpChannelParent.cpp +++ b/netwerk/protocol/http/HttpChannelParent.cpp @@ -11,6 +11,7 @@ #include "mozilla/ipc/IPCStreamUtils.h" #include "mozilla/net/HttpChannelParent.h" #include "mozilla/dom/ContentParent.h" +#include "mozilla/dom/ContentProcessManager.h" #include "mozilla/dom/Element.h" #include "mozilla/dom/ServiceWorkerUtils.h" #include "mozilla/dom/BrowserParent.h" @@ -20,7 +21,7 @@ #include "mozilla/UniquePtr.h" #include "mozilla/Unused.h" #include "HttpBackgroundChannelParent.h" -#include "HttpChannelParentListener.h" +#include "ParentChannelListener.h" #include "nsHttpHandler.h" #include "nsNetCID.h" #include "nsNetUtil.h" @@ -282,6 +283,8 @@ NS_INTERFACE_MAP_BEGIN(HttpChannelParent) NS_INTERFACE_MAP_ENTRY(nsIParentRedirectingChannel) NS_INTERFACE_MAP_ENTRY(nsIDeprecationWarner) NS_INTERFACE_MAP_ENTRY(nsIAsyncVerifyRedirectReadyCallback) + NS_INTERFACE_MAP_ENTRY(nsIChannelEventSink) + NS_INTERFACE_MAP_ENTRY(nsIRedirectResultListener) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIParentRedirectingChannel) NS_INTERFACE_MAP_ENTRY_CONCRETE(HttpChannelParent) NS_INTERFACE_MAP_END @@ -350,7 +353,7 @@ void HttpChannelParent::AsyncOpenFailed(nsresult aRv) { MOZ_ASSERT(NS_FAILED(aRv)); // Break the reference cycle among HttpChannelParent, - // HttpChannelParentListener, and nsHttpChannel to avoid memory leakage. + // ParentChannelListener, and nsHttpChannel to avoid memory leakage. mChannel = nullptr; mParentListener = nullptr; @@ -508,8 +511,8 @@ bool HttpChannelParent::DoAsyncOpen( } } - RefPtr parentListener = - new HttpChannelParentListener(this); + RefPtr parentListener = + new ParentChannelListener(this); httpChannel->SetRequestMethod(nsDependentCString(requestMethod.get())); @@ -731,7 +734,7 @@ bool HttpChannelParent::ConnectChannel(const uint32_t& registrarId, nsCOMPtr controller; NS_QueryNotificationCallbacks(channel, controller); - RefPtr parentListener = do_QueryObject(controller); + RefPtr parentListener = do_QueryObject(controller); MOZ_ASSERT(parentListener); parentListener->SetupInterceptionAfterRedirect(shouldIntercept); @@ -927,7 +930,7 @@ mozilla::ipc::IPCResult HttpChannelParent::RecvRedirect2Verify( MOZ_ASSERT(redirectReg); nsCOMPtr redirectParentChannel; - rv = redirectReg->GetParentChannel(mRedirectRegistrarId, + rv = redirectReg->GetParentChannel(mRedirectChannelId, getter_AddRefs(redirectParentChannel)); MOZ_ASSERT(redirectParentChannel); if (!redirectParentChannel) { @@ -988,16 +991,21 @@ void HttpChannelParent::ContinueRedirect2Verify(const nsresult& aResult) { if (!mRedirectCallback) { // This should according the logic never happen, log the situation. - if (mReceivedRedirect2Verify) + if (mReceivedRedirect2Verify) { LOG(("RecvRedirect2Verify[%p]: Duplicate fire", this)); - if (mSentRedirect1BeginFailed) + } + if (mSentRedirect1BeginFailed) { LOG(("RecvRedirect2Verify[%p]: Send to child failed", this)); - if ((mRedirectRegistrarId > 0) && NS_FAILED(aResult)) + } + if ((mRedirectChannelId > 0) && NS_FAILED(aResult)) { LOG(("RecvRedirect2Verify[%p]: Redirect failed", this)); - if ((mRedirectRegistrarId > 0) && NS_SUCCEEDED(aResult)) + } + if ((mRedirectChannelId > 0) && NS_SUCCEEDED(aResult)) { LOG(("RecvRedirect2Verify[%p]: Redirect succeeded", this)); - if (!mRedirectChannel) + } + if (!mRedirectChannel) { LOG(("RecvRedirect2Verify[%p]: Missing redirect channel", this)); + } NS_ERROR( "Unexpcted call to HttpChannelParent::RecvRedirect2Verify, " @@ -1234,15 +1242,13 @@ void HttpChannelParent::MaybeFlushPendingDiversion() { static void FinishCrossProcessRedirect(nsHttpChannel* channel, nsresult status) { if (NS_SUCCEEDED(status)) { - nsCOMPtr controller; - NS_QueryNotificationCallbacks(channel, controller); - RefPtr parentListener = - do_QueryObject(controller); - MOZ_ASSERT(parentListener); + nsCOMPtr redirectListener; + NS_QueryNotificationCallbacks(channel, redirectListener); + MOZ_ASSERT(redirectListener); - // This updates HttpChannelParentListener to point to this parent and at + // This updates ParentChannelListener to point to this parent and at // the same time cancels the old channel. - parentListener->OnRedirectResult(status == NS_OK); + redirectListener->OnRedirectResult(true); } channel->OnRedirectVerifyCallback(status); @@ -1826,7 +1832,7 @@ HttpChannelParent::OnStatus(nsIRequest* aRequest, nsISupports* aContext, //----------------------------------------------------------------------------- NS_IMETHODIMP -HttpChannelParent::SetParentListener(HttpChannelParentListener* aListener) { +HttpChannelParent::SetParentListener(ParentChannelListener* aListener) { LOG(("HttpChannelParent::SetParentListener [this=%p aListener=%p]\n", this, aListener)); MOZ_ASSERT(aListener); @@ -1938,14 +1944,22 @@ HttpChannelParent::Delete() { //----------------------------------------------------------------------------- NS_IMETHODIMP -HttpChannelParent::StartRedirect(uint32_t registrarId, nsIChannel* newChannel, - uint32_t redirectFlags, +HttpChannelParent::StartRedirect(nsIChannel* newChannel, uint32_t redirectFlags, nsIAsyncVerifyRedirectCallback* callback) { nsresult rv; - LOG(("HttpChannelParent::StartRedirect [this=%p, registrarId=%" PRIu32 " " - "newChannel=%p callback=%p]\n", - this, registrarId, newChannel, callback)); + LOG(("HttpChannelParent::StartRedirect [this=%p, newChannel=%p callback=%p]", + this, newChannel, callback)); + + // Register the new channel and obtain id for it + nsCOMPtr registrar = + RedirectChannelRegistrar::GetOrCreate(); + MOZ_ASSERT(registrar); + + rv = registrar->RegisterChannel(newChannel, &mRedirectChannelId); + NS_ENSURE_SUCCESS(rv, rv); + + LOG(("Registered %p channel under id=%d", newChannel, mRedirectChannelId)); if (mIPCClosed) { return NS_BINDING_ABORTED; @@ -1987,7 +2001,7 @@ HttpChannelParent::StartRedirect(uint32_t registrarId, nsIChannel* newChannel, // Re-link the HttpChannelParent to the new InterceptedHttpChannel. nsCOMPtr linkedChannel; - rv = NS_LinkRedirectChannels(registrarId, this, + rv = NS_LinkRedirectChannels(mRedirectChannelId, this, getter_AddRefs(linkedChannel)); NS_ENSURE_SUCCESS(rv, rv); MOZ_ASSERT(linkedChannel == newChannel); @@ -2052,7 +2066,7 @@ HttpChannelParent::StartRedirect(uint32_t registrarId, nsIChannel* newChannel, bool result = false; if (!mIPCClosed) { - result = SendRedirect1Begin(registrarId, uriParams, newLoadFlags, + result = SendRedirect1Begin(mRedirectChannelId, uriParams, newLoadFlags, redirectFlags, loadInfoForwarderArg, *responseHead, secInfoSerialization, channelId, mChannel->GetPeerAddr(), timing); @@ -2063,11 +2077,6 @@ HttpChannelParent::StartRedirect(uint32_t registrarId, nsIChannel* newChannel, return NS_BINDING_ABORTED; } - // Bug 621446 investigation - // Store registrar Id of the new channel to find the redirect - // HttpChannelParent later in verification phase. - mRedirectRegistrarId = registrarId; - // Result is handled in RecvRedirect2Verify above mRedirectChannel = newChannel; @@ -2085,9 +2094,8 @@ void HttpChannelParent::CancelChildCrossProcessRedirect() { } } -already_AddRefed -HttpChannelParent::GetParentListener() { - RefPtr listener = mParentListener; +already_AddRefed HttpChannelParent::GetParentListener() { + RefPtr listener = mParentListener; return listener.forget(); } @@ -2529,5 +2537,154 @@ nsresult HttpChannelParent::LogMimeTypeMismatch(const nsACString& aMessageName, return NS_OK; } +//----------------------------------------------------------------------------- +// nsIChannelEventSink +//----------------------------------------------------------------------------- + +NS_IMETHODIMP +HttpChannelParent::AsyncOnChannelRedirect( + nsIChannel* aOldChannel, nsIChannel* aNewChannel, uint32_t aRedirectFlags, + nsIAsyncVerifyRedirectCallback* aCallback) { + LOG( + ("HttpChannelParent::AsyncOnChannelRedirect [this=%p, old=%p, " + "new=%p, flags=%u]", + this, aOldChannel, aNewChannel, aRedirectFlags)); + + return StartRedirect(aNewChannel, aRedirectFlags, aCallback); +} + +//----------------------------------------------------------------------------- +// nsIRedirectResultListener +//----------------------------------------------------------------------------- + +NS_IMETHODIMP +HttpChannelParent::OnRedirectResult(bool succeeded) { + LOG(("HttpChannelParent::OnRedirectResult [this=%p, suc=%d]", this, + succeeded)); + + nsresult rv; + + nsCOMPtr redirectChannel; + if (mRedirectChannelId) { + nsCOMPtr registrar = + RedirectChannelRegistrar::GetOrCreate(); + MOZ_ASSERT(registrar); + + rv = registrar->GetParentChannel(mRedirectChannelId, + getter_AddRefs(redirectChannel)); + if (NS_FAILED(rv) || !redirectChannel) { + // Redirect might get canceled before we got AsyncOnChannelRedirect + LOG(("Registered parent channel not found under id=%d", + mRedirectChannelId)); + + nsCOMPtr newChannel; + rv = registrar->GetRegisteredChannel(mRedirectChannelId, + getter_AddRefs(newChannel)); + MOZ_ASSERT(newChannel, "Already registered channel not found"); + + if (NS_SUCCEEDED(rv)) { + newChannel->Cancel(NS_BINDING_ABORTED); + } + } + + // Release all previously registered channels, they are no longer need to be + // kept in the registrar from this moment. + registrar->DeregisterChannels(mRedirectChannelId); + + mRedirectChannelId = 0; + } + + if (!redirectChannel) { + succeeded = false; + } + + CompleteRedirect(succeeded); + + if (succeeded) { + if (!SameCOMIdentity(redirectChannel, + static_cast(this))) { + Delete(); + mParentListener->SetListenerAfterRedirect(redirectChannel); + redirectChannel->SetParentListener(mParentListener); + } + } else if (redirectChannel) { + // Delete the redirect target channel: continue using old channel + redirectChannel->Delete(); + } + + return NS_OK; +} + +nsresult HttpChannelParent::TriggerCrossProcessRedirect(nsIChannel* aChannel, + nsILoadInfo* aLoadInfo, + uint64_t aIdentifier) { + CancelChildCrossProcessRedirect(); + + nsCOMPtr channel = aChannel; + RefPtr httpChannel = do_QueryObject(channel); + RefPtr p = + httpChannel->TakeRedirectContentProcessIdPromise(); + nsCOMPtr loadInfo = aLoadInfo; + + RefPtr self = this; + p->Then( + GetMainThreadSerialEventTarget(), __func__, + [=](uint64_t cpId) { + nsresult rv; + + // Register the new channel and obtain id for it + nsCOMPtr registrar = + RedirectChannelRegistrar::GetOrCreate(); + MOZ_ASSERT(registrar); + rv = registrar->RegisterChannel(channel, &self->mRedirectChannelId); + NS_ENSURE_SUCCESS(rv, rv); + + LOG(("Registered %p channel under id=%d", channel.get(), + self->mRedirectChannelId)); + + Maybe loadInfoArgs; + MOZ_ALWAYS_SUCCEEDS(LoadInfoToLoadInfoArgs(loadInfo, &loadInfoArgs)); + + uint32_t newLoadFlags = nsIRequest::LOAD_NORMAL; + MOZ_ALWAYS_SUCCEEDS(channel->GetLoadFlags(&newLoadFlags)); + + nsCOMPtr uri; + channel->GetURI(getter_AddRefs(uri)); + + nsCOMPtr originalURI; + channel->GetOriginalURI(getter_AddRefs(originalURI)); + + uint64_t channelId; + MOZ_ALWAYS_SUCCEEDS(httpChannel->GetChannelId(&channelId)); + + uint32_t redirectMode = nsIHttpChannelInternal::REDIRECT_MODE_FOLLOW; + nsCOMPtr internalChannel = + do_QueryInterface(channel); + if (internalChannel) { + MOZ_ALWAYS_SUCCEEDS(internalChannel->GetRedirectMode(&redirectMode)); + } + + dom::ContentParent* cp = + dom::ContentProcessManager::GetSingleton()->GetContentProcessById( + ContentParentId{cpId}); + if (!cp) { + return NS_ERROR_UNEXPECTED; + } + auto result = cp->SendCrossProcessRedirect( + self->mRedirectChannelId, uri, newLoadFlags, loadInfoArgs, + channelId, originalURI, aIdentifier, redirectMode); + + MOZ_ASSERT(result, "SendCrossProcessRedirect failed"); + + return result ? NS_OK : NS_ERROR_UNEXPECTED; + }, + [httpChannel](nsresult aStatus) { + MOZ_ASSERT(NS_FAILED(aStatus), "Status should be error"); + httpChannel->OnRedirectVerifyCallback(aStatus); + }); + + return NS_OK; +} + } // namespace net } // namespace mozilla diff --git a/netwerk/protocol/http/HttpChannelParent.h b/netwerk/protocol/http/HttpChannelParent.h index af27816b8ea9..e2569729cc74 100644 --- a/netwerk/protocol/http/HttpChannelParent.h +++ b/netwerk/protocol/http/HttpChannelParent.h @@ -17,6 +17,8 @@ #include "nsIObserver.h" #include "nsIParentRedirectingChannel.h" #include "nsIProgressEventSink.h" +#include "nsIChannelEventSink.h" +#include "nsIRedirectResultListener.h" #include "nsHttpChannel.h" #include "nsIAuthPromptProvider.h" #include "mozilla/dom/ipc/IdType.h" @@ -41,7 +43,7 @@ class PBrowserOrId; namespace net { class HttpBackgroundChannelParent; -class HttpChannelParentListener; +class ParentChannelListener; class ChannelEventQueue; // Note: nsIInterfaceRequestor must be the first base so that do_QueryObject() @@ -56,7 +58,9 @@ class HttpChannelParent final : public nsIInterfaceRequestor, public nsIAuthPromptProvider, public nsIDeprecationWarner, public HttpChannelSecurityWarningReporter, - public nsIAsyncVerifyRedirectReadyCallback { + public nsIAsyncVerifyRedirectReadyCallback, + public nsIChannelEventSink, + public nsIRedirectResultListener { virtual ~HttpChannelParent(); public: @@ -70,6 +74,8 @@ class HttpChannelParent final : public nsIInterfaceRequestor, NS_DECL_NSIAUTHPROMPTPROVIDER NS_DECL_NSIDEPRECATIONWARNER NS_DECL_NSIASYNCVERIFYREDIRECTREADYCALLBACK + NS_DECL_NSICHANNELEVENTSINK + NS_DECL_NSIREDIRECTRESULTLISTENER NS_DECLARE_STATIC_IID_ACCESSOR(HTTP_CHANNEL_PARENT_IID) @@ -129,7 +135,11 @@ class HttpChannelParent final : public nsIInterfaceRequestor, // child channel. void CancelChildCrossProcessRedirect(); - already_AddRefed GetParentListener(); + already_AddRefed GetParentListener(); + + nsresult TriggerCrossProcessRedirect(nsIChannel* oldChannel, + nsILoadInfo* aLoadInfo, + uint64_t aIdentifier); protected: // used to connect redirected-to channel in parent with just created @@ -218,7 +228,7 @@ class HttpChannelParent final : public nsIInterfaceRequestor, // Asynchronously calls NotifyDiversionFailed. void FailDiversion(nsresult aErrorCode); - friend class HttpChannelParentListener; + friend class ParentChannelListener; RefPtr mBrowserParent; MOZ_MUST_USE nsresult ReportSecurityMessage( @@ -287,7 +297,7 @@ class HttpChannelParent final : public nsIInterfaceRequestor, nsCOMPtr mLoadContext; RefPtr mHttpHandler; - RefPtr mParentListener; + RefPtr mParentListener; // The listener we are diverting to or will divert to if mPendingDiversion // is set. nsCOMPtr mDivertListener; @@ -308,7 +318,7 @@ class HttpChannelParent final : public nsIInterfaceRequestor, // Corresponding redirect channel registrar Id. 0 means redirection is not // started. - uint32_t mRedirectRegistrarId = 0; + uint32_t mRedirectChannelId = 0; PBOverrideStatus mPBOverride; diff --git a/netwerk/protocol/http/HttpChannelParentListener.cpp b/netwerk/protocol/http/HttpChannelParentListener.cpp deleted file mode 100644 index 3e5161d0f6b3..000000000000 --- a/netwerk/protocol/http/HttpChannelParentListener.cpp +++ /dev/null @@ -1,514 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set sw=2 ts=8 et tw=80 : */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -// HttpLog.h should generally be included first -#include "HttpLog.h" - -#include "HttpChannelParentListener.h" -#include "mozilla/dom/ContentParent.h" -#include "mozilla/dom/ContentProcessManager.h" -#include "mozilla/dom/ServiceWorkerInterceptController.h" -#include "mozilla/dom/ServiceWorkerUtils.h" -#include "mozilla/net/HttpChannelParent.h" -#include "mozilla/net/RedirectChannelRegistrar.h" -#include "mozilla/Unused.h" -#include "nsIAuthPrompt.h" -#include "nsIAuthPrompt2.h" -#include "nsIHttpHeaderVisitor.h" -#include "nsIRemoteTab.h" -#include "nsIPromptFactory.h" -#include "nsIWindowWatcher.h" -#include "nsQueryObject.h" - -using mozilla::Unused; -using mozilla::dom::ServiceWorkerInterceptController; -using mozilla::dom::ServiceWorkerParentInterceptEnabled; - -namespace mozilla { -namespace net { - -HttpChannelParentListener::HttpChannelParentListener( - HttpChannelParent* aInitialChannel) - : mNextListener(aInitialChannel), - mRedirectChannelId(0), - mSuspendedForDiversion(false), - mShouldIntercept(false), - mShouldSuspendIntercept(false), - mInterceptCanceled(false) { - LOG(( - "HttpChannelParentListener::HttpChannelParentListener [this=%p, next=%p]", - this, aInitialChannel)); - - if (ServiceWorkerParentInterceptEnabled()) { - mInterceptController = new ServiceWorkerInterceptController(); - } -} - -HttpChannelParentListener::~HttpChannelParentListener() { - LOG(("HttpChannelParentListener::~HttpChannelParentListener %p", this)); -} - -//----------------------------------------------------------------------------- -// HttpChannelParentListener::nsISupports -//----------------------------------------------------------------------------- - -NS_IMPL_ADDREF(HttpChannelParentListener) -NS_IMPL_RELEASE(HttpChannelParentListener) -NS_INTERFACE_MAP_BEGIN(HttpChannelParentListener) - NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor) - NS_INTERFACE_MAP_ENTRY(nsIStreamListener) - NS_INTERFACE_MAP_ENTRY(nsIRequestObserver) - NS_INTERFACE_MAP_ENTRY(nsIChannelEventSink) - NS_INTERFACE_MAP_ENTRY(nsIRedirectResultListener) - NS_INTERFACE_MAP_ENTRY(nsINetworkInterceptController) - NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIInterfaceRequestor) - NS_INTERFACE_MAP_ENTRY_CONCRETE(HttpChannelParentListener) -NS_INTERFACE_MAP_END - -//----------------------------------------------------------------------------- -// HttpChannelParentListener::nsIRequestObserver -//----------------------------------------------------------------------------- - -NS_IMETHODIMP -HttpChannelParentListener::OnStartRequest(nsIRequest* aRequest) { - MOZ_RELEASE_ASSERT(!mSuspendedForDiversion, - "Cannot call OnStartRequest if suspended for diversion!"); - - if (!mNextListener) return NS_ERROR_UNEXPECTED; - - LOG(("HttpChannelParentListener::OnStartRequest [this=%p]\n", this)); - return mNextListener->OnStartRequest(aRequest); -} - -NS_IMETHODIMP -HttpChannelParentListener::OnStopRequest(nsIRequest* aRequest, - nsresult aStatusCode) { - MOZ_RELEASE_ASSERT(!mSuspendedForDiversion, - "Cannot call OnStopRequest if suspended for diversion!"); - - if (!mNextListener) return NS_ERROR_UNEXPECTED; - - LOG(("HttpChannelParentListener::OnStopRequest: [this=%p status=%" PRIu32 - "]\n", - this, static_cast(aStatusCode))); - nsresult rv = mNextListener->OnStopRequest(aRequest, aStatusCode); - - mNextListener = nullptr; - return rv; -} - -//----------------------------------------------------------------------------- -// HttpChannelParentListener::nsIStreamListener -//----------------------------------------------------------------------------- - -NS_IMETHODIMP -HttpChannelParentListener::OnDataAvailable(nsIRequest* aRequest, - nsIInputStream* aInputStream, - uint64_t aOffset, uint32_t aCount) { - MOZ_RELEASE_ASSERT(!mSuspendedForDiversion, - "Cannot call OnDataAvailable if suspended for diversion!"); - - if (!mNextListener) return NS_ERROR_UNEXPECTED; - - LOG(("HttpChannelParentListener::OnDataAvailable [this=%p]\n", this)); - return mNextListener->OnDataAvailable(aRequest, aInputStream, aOffset, - aCount); -} - -//----------------------------------------------------------------------------- -// HttpChannelParentListener::nsIInterfaceRequestor -//----------------------------------------------------------------------------- - -NS_IMETHODIMP -HttpChannelParentListener::GetInterface(const nsIID& aIID, void** result) { - if (aIID.Equals(NS_GET_IID(nsIChannelEventSink)) || - aIID.Equals(NS_GET_IID(nsINetworkInterceptController)) || - aIID.Equals(NS_GET_IID(nsIRedirectResultListener))) { - return QueryInterface(aIID, result); - } - - nsCOMPtr ir; - if (mNextListener && NS_SUCCEEDED(CallQueryInterface(mNextListener.get(), - getter_AddRefs(ir)))) { - return ir->GetInterface(aIID, result); - } - - if (aIID.Equals(NS_GET_IID(nsIAuthPrompt)) || - aIID.Equals(NS_GET_IID(nsIAuthPrompt2))) { - nsresult rv; - nsCOMPtr wwatch = - do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv); - NS_ENSURE_SUCCESS(rv, rv); - - return wwatch->GetPrompt(nullptr, aIID, reinterpret_cast(result)); - } - - return NS_NOINTERFACE; -} - -//----------------------------------------------------------------------------- -// HttpChannelParentListener::nsIChannelEventSink -//----------------------------------------------------------------------------- -nsresult HttpChannelParentListener::TriggerCrossProcessRedirect( - nsIChannel* aChannel, nsILoadInfo* aLoadInfo, uint64_t aIdentifier) { - RefPtr channelParent = do_QueryObject(mNextListener); - MOZ_ASSERT(channelParent); - channelParent->CancelChildCrossProcessRedirect(); - - nsCOMPtr channel = aChannel; - RefPtr httpChannel = do_QueryObject(channel); - RefPtr p = - httpChannel->TakeRedirectContentProcessIdPromise(); - nsCOMPtr loadInfo = aLoadInfo; - - RefPtr self = this; - p->Then( - GetMainThreadSerialEventTarget(), __func__, - [=](uint64_t cpId) { - nsresult rv; - - // Register the new channel and obtain id for it - nsCOMPtr registrar = - RedirectChannelRegistrar::GetOrCreate(); - MOZ_ASSERT(registrar); - rv = registrar->RegisterChannel(channel, &self->mRedirectChannelId); - NS_ENSURE_SUCCESS(rv, rv); - - LOG(("Registered %p channel under id=%d", channel.get(), - self->mRedirectChannelId)); - - Maybe loadInfoArgs; - MOZ_ALWAYS_SUCCEEDS(LoadInfoToLoadInfoArgs(loadInfo, &loadInfoArgs)); - - uint32_t newLoadFlags = nsIRequest::LOAD_NORMAL; - MOZ_ALWAYS_SUCCEEDS(channel->GetLoadFlags(&newLoadFlags)); - - nsCOMPtr uri; - channel->GetURI(getter_AddRefs(uri)); - - nsCOMPtr originalURI; - channel->GetOriginalURI(getter_AddRefs(originalURI)); - - uint64_t channelId; - MOZ_ALWAYS_SUCCEEDS(httpChannel->GetChannelId(&channelId)); - - uint32_t redirectMode = nsIHttpChannelInternal::REDIRECT_MODE_FOLLOW; - nsCOMPtr internalChannel = - do_QueryInterface(channel); - if (internalChannel) { - MOZ_ALWAYS_SUCCEEDS(internalChannel->GetRedirectMode(&redirectMode)); - } - - dom::ContentParent* cp = - dom::ContentProcessManager::GetSingleton()->GetContentProcessById( - ContentParentId{cpId}); - if (!cp) { - return NS_ERROR_UNEXPECTED; - } - auto result = cp->SendCrossProcessRedirect( - self->mRedirectChannelId, uri, newLoadFlags, loadInfoArgs, - channelId, originalURI, aIdentifier, redirectMode); - - MOZ_ASSERT(result, "SendCrossProcessRedirect failed"); - - return result ? NS_OK : NS_ERROR_UNEXPECTED; - }, - [httpChannel](nsresult aStatus) { - MOZ_ASSERT(NS_FAILED(aStatus), "Status should be error"); - httpChannel->OnRedirectVerifyCallback(aStatus); - }); - - return NS_OK; -} - -NS_IMETHODIMP -HttpChannelParentListener::AsyncOnChannelRedirect( - nsIChannel* aOldChannel, nsIChannel* aNewChannel, uint32_t aRedirectFlags, - nsIAsyncVerifyRedirectCallback* aCallback) { - LOG( - ("HttpChannelParentListener::AsyncOnChannelRedirect [this=%p, old=%p, " - "new=%p, flags=%u]", - this, aOldChannel, aNewChannel, aRedirectFlags)); - - nsresult rv; - - nsCOMPtr activeRedirectingChannel = - do_QueryInterface(mNextListener); - if (!activeRedirectingChannel) { - NS_ERROR( - "Channel got a redirect response, but doesn't implement " - "nsIParentRedirectingChannel to handle it."); - return NS_ERROR_NOT_IMPLEMENTED; - } - - // Register the new channel and obtain id for it - nsCOMPtr registrar = - RedirectChannelRegistrar::GetOrCreate(); - MOZ_ASSERT(registrar); - - rv = registrar->RegisterChannel(aNewChannel, &mRedirectChannelId); - NS_ENSURE_SUCCESS(rv, rv); - - LOG(("Registered %p channel under id=%d", aNewChannel, mRedirectChannelId)); - - return activeRedirectingChannel->StartRedirect( - mRedirectChannelId, aNewChannel, aRedirectFlags, aCallback); -} - -//----------------------------------------------------------------------------- -// HttpChannelParentListener::nsIRedirectResultListener -//----------------------------------------------------------------------------- - -NS_IMETHODIMP -HttpChannelParentListener::OnRedirectResult(bool succeeded) { - LOG(("HttpChannelParentListener::OnRedirectResult [this=%p, suc=%d]", this, - succeeded)); - - nsresult rv; - - nsCOMPtr redirectChannel; - if (mRedirectChannelId) { - nsCOMPtr registrar = - RedirectChannelRegistrar::GetOrCreate(); - MOZ_ASSERT(registrar); - - rv = registrar->GetParentChannel(mRedirectChannelId, - getter_AddRefs(redirectChannel)); - if (NS_FAILED(rv) || !redirectChannel) { - // Redirect might get canceled before we got AsyncOnChannelRedirect - LOG(("Registered parent channel not found under id=%d", - mRedirectChannelId)); - - nsCOMPtr newChannel; - rv = registrar->GetRegisteredChannel(mRedirectChannelId, - getter_AddRefs(newChannel)); - MOZ_ASSERT(newChannel, "Already registered channel not found"); - - if (NS_SUCCEEDED(rv)) newChannel->Cancel(NS_BINDING_ABORTED); - } - - // Release all previously registered channels, they are no longer need to be - // kept in the registrar from this moment. - registrar->DeregisterChannels(mRedirectChannelId); - - mRedirectChannelId = 0; - } - - if (!redirectChannel) { - succeeded = false; - } - - nsCOMPtr activeRedirectingChannel = - do_QueryInterface(mNextListener); - MOZ_ASSERT(activeRedirectingChannel, - "Channel finished a redirect response, but doesn't implement " - "nsIParentRedirectingChannel to complete it."); - - if (activeRedirectingChannel) { - activeRedirectingChannel->CompleteRedirect(succeeded); - } else { - succeeded = false; - } - - if (succeeded) { - // Switch to redirect channel and delete the old one. Only do this - // if we are actually changing channels. During a service worker - // interception internal redirect we preserve the same HttpChannelParent. - if (!SameCOMIdentity(redirectChannel, mNextListener)) { - nsCOMPtr parent; - parent = do_QueryInterface(mNextListener); - MOZ_ASSERT(parent); - parent->Delete(); - mInterceptCanceled = false; - mNextListener = redirectChannel; - MOZ_ASSERT(mNextListener); - redirectChannel->SetParentListener(this); - } - } else if (redirectChannel) { - // Delete the redirect target channel: continue using old channel - redirectChannel->Delete(); - } - - return NS_OK; -} - -//----------------------------------------------------------------------------- -// HttpChannelParentListener::nsINetworkInterceptController -//----------------------------------------------------------------------------- - -NS_IMETHODIMP -HttpChannelParentListener::ShouldPrepareForIntercept(nsIURI* aURI, - nsIChannel* aChannel, - bool* aShouldIntercept) { - // If parent-side interception is enabled just forward to the real - // network controler. - if (mInterceptController) { - return mInterceptController->ShouldPrepareForIntercept(aURI, aChannel, - aShouldIntercept); - } - *aShouldIntercept = mShouldIntercept; - return NS_OK; -} - -class HeaderVisitor final : public nsIHttpHeaderVisitor { - nsCOMPtr mChannel; - ~HeaderVisitor() = default; - - public: - explicit HeaderVisitor(nsIInterceptedChannel* aChannel) - : mChannel(aChannel) {} - - NS_DECL_ISUPPORTS - - NS_IMETHOD VisitHeader(const nsACString& aHeader, - const nsACString& aValue) override { - mChannel->SynthesizeHeader(aHeader, aValue); - return NS_OK; - } -}; - -NS_IMPL_ISUPPORTS(HeaderVisitor, nsIHttpHeaderVisitor) - -class FinishSynthesizedResponse : public Runnable { - nsCOMPtr mChannel; - - public: - explicit FinishSynthesizedResponse(nsIInterceptedChannel* aChannel) - : Runnable("net::FinishSynthesizedResponse"), mChannel(aChannel) {} - - NS_IMETHOD Run() override { - // The URL passed as an argument here doesn't matter, since the child will - // receive a redirection notification as a result of this synthesized - // response. - mChannel->StartSynthesizedResponse(nullptr, nullptr, nullptr, - EmptyCString(), false); - mChannel->FinishSynthesizedResponse(); - return NS_OK; - } -}; - -NS_IMETHODIMP -HttpChannelParentListener::ChannelIntercepted(nsIInterceptedChannel* aChannel) { - // If parent-side interception is enabled just forward to the real - // network controler. - if (mInterceptController) { - return mInterceptController->ChannelIntercepted(aChannel); - } - - // Its possible for the child-side interception to complete and tear down - // the actor before we even get this parent-side interception notification. - // In this case we want to let the interception succeed, but then immediately - // cancel it. If we return an error code from here then it might get - // propagated back to the child process where the interception did not - // encounter an error. Therefore cancel the new channel asynchronously from a - // runnable. - if (mInterceptCanceled) { - nsCOMPtr r = NewRunnableMethod( - "HttpChannelParentListener::CancelInterception", aChannel, - &nsIInterceptedChannel::CancelInterception, NS_BINDING_ABORTED); - MOZ_ALWAYS_SUCCEEDS(SystemGroup::Dispatch(TaskCategory::Other, r.forget())); - return NS_OK; - } - - if (mShouldSuspendIntercept) { - mInterceptedChannel = aChannel; - return NS_OK; - } - - nsAutoCString statusText; - mSynthesizedResponseHead->StatusText(statusText); - aChannel->SynthesizeStatus(mSynthesizedResponseHead->Status(), statusText); - nsCOMPtr visitor = new HeaderVisitor(aChannel); - DebugOnly rv = mSynthesizedResponseHead->VisitHeaders( - visitor, nsHttpHeaderArray::eFilterResponse); - MOZ_ASSERT(NS_SUCCEEDED(rv)); - - nsCOMPtr event = new FinishSynthesizedResponse(aChannel); - NS_DispatchToCurrentThread(event); - - mSynthesizedResponseHead = nullptr; - - MOZ_ASSERT(mNextListener); - RefPtr channel = do_QueryObject(mNextListener); - MOZ_ASSERT(channel); - channel->ResponseSynthesized(); - - return NS_OK; -} - -//----------------------------------------------------------------------------- - -nsresult HttpChannelParentListener::SuspendForDiversion() { - if (NS_WARN_IF(mSuspendedForDiversion)) { - MOZ_ASSERT(!mSuspendedForDiversion, "Cannot SuspendForDiversion twice!"); - return NS_ERROR_UNEXPECTED; - } - - // While this is set, no OnStart/OnData/OnStop callbacks should be forwarded - // to mNextListener. - mSuspendedForDiversion = true; - - return NS_OK; -} - -nsresult HttpChannelParentListener::ResumeForDiversion() { - MOZ_RELEASE_ASSERT(mSuspendedForDiversion, "Must already be suspended!"); - - // Allow OnStart/OnData/OnStop callbacks to be forwarded to mNextListener. - mSuspendedForDiversion = false; - - return NS_OK; -} - -nsresult HttpChannelParentListener::DivertTo(nsIStreamListener* aListener) { - MOZ_ASSERT(aListener); - MOZ_RELEASE_ASSERT(mSuspendedForDiversion, "Must already be suspended!"); - - // Reset mInterceptCanceled back to false every time a new listener is set. - // We only want to cancel the interception if our current listener has - // signaled its cleaning up. - mInterceptCanceled = false; - - mNextListener = aListener; - - return ResumeForDiversion(); -} - -void HttpChannelParentListener::SetupInterception( - const nsHttpResponseHead& aResponseHead) { - mSynthesizedResponseHead = new nsHttpResponseHead(aResponseHead); - mShouldIntercept = true; -} - -void HttpChannelParentListener::SetupInterceptionAfterRedirect( - bool aShouldIntercept) { - mShouldIntercept = aShouldIntercept; - if (mShouldIntercept) { - // When an interception occurs, this channel should suspend all further - // activity. It will be torn down and recreated if necessary. - mShouldSuspendIntercept = true; - } -} - -void HttpChannelParentListener::ClearInterceptedChannel( - nsIStreamListener* aListener) { - // Only cancel the interception if this is from our current listener. We - // can get spurious calls here from other HttpChannelParent instances being - // destroyed asynchronously. - if (!SameCOMIdentity(mNextListener, aListener)) { - return; - } - if (mInterceptedChannel) { - mInterceptedChannel->CancelInterception(NS_ERROR_INTERCEPTION_FAILED); - mInterceptedChannel = nullptr; - } - // Note that channel interception has been canceled. If we got this before - // the interception even occured we will trigger the cancel later. - mInterceptCanceled = true; -} - -} // namespace net -} // namespace mozilla diff --git a/netwerk/protocol/http/ParentChannelListener.cpp b/netwerk/protocol/http/ParentChannelListener.cpp new file mode 100644 index 000000000000..3b2fbe264fbb --- /dev/null +++ b/netwerk/protocol/http/ParentChannelListener.cpp @@ -0,0 +1,325 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set sw=2 ts=8 et tw=80 : */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// HttpLog.h should generally be included first +#include "HttpLog.h" + +#include "ParentChannelListener.h" +#include "mozilla/dom/ContentParent.h" +#include "mozilla/dom/ServiceWorkerInterceptController.h" +#include "mozilla/dom/ServiceWorkerUtils.h" +#include "mozilla/net/HttpChannelParent.h" +#include "mozilla/net/RedirectChannelRegistrar.h" +#include "mozilla/Unused.h" +#include "nsIAuthPrompt.h" +#include "nsIAuthPrompt2.h" +#include "nsIHttpHeaderVisitor.h" +#include "nsIRemoteTab.h" +#include "nsIPromptFactory.h" +#include "nsIWindowWatcher.h" +#include "nsQueryObject.h" + +using mozilla::Unused; +using mozilla::dom::ServiceWorkerInterceptController; +using mozilla::dom::ServiceWorkerParentInterceptEnabled; + +namespace mozilla { +namespace net { + +ParentChannelListener::ParentChannelListener(nsIStreamListener* aListener) + : mNextListener(aListener), + mSuspendedForDiversion(false), + mShouldIntercept(false), + mShouldSuspendIntercept(false), + mInterceptCanceled(false) { + LOG(("ParentChannelListener::ParentChannelListener [this=%p, next=%p]", this, + aListener)); + + if (ServiceWorkerParentInterceptEnabled()) { + mInterceptController = new ServiceWorkerInterceptController(); + } +} + +ParentChannelListener::~ParentChannelListener() { + LOG(("ParentChannelListener::~ParentChannelListener %p", this)); +} + +//----------------------------------------------------------------------------- +// ParentChannelListener::nsISupports +//----------------------------------------------------------------------------- + +NS_IMPL_ADDREF(ParentChannelListener) +NS_IMPL_RELEASE(ParentChannelListener) +NS_INTERFACE_MAP_BEGIN(ParentChannelListener) + NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor) + NS_INTERFACE_MAP_ENTRY(nsIStreamListener) + NS_INTERFACE_MAP_ENTRY(nsIRequestObserver) + NS_INTERFACE_MAP_ENTRY(nsINetworkInterceptController) + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIInterfaceRequestor) + NS_INTERFACE_MAP_ENTRY_CONCRETE(ParentChannelListener) +NS_INTERFACE_MAP_END + +//----------------------------------------------------------------------------- +// ParentChannelListener::nsIRequestObserver +//----------------------------------------------------------------------------- + +NS_IMETHODIMP +ParentChannelListener::OnStartRequest(nsIRequest* aRequest) { + MOZ_RELEASE_ASSERT(!mSuspendedForDiversion, + "Cannot call OnStartRequest if suspended for diversion!"); + + if (!mNextListener) return NS_ERROR_UNEXPECTED; + + LOG(("ParentChannelListener::OnStartRequest [this=%p]\n", this)); + return mNextListener->OnStartRequest(aRequest); +} + +NS_IMETHODIMP +ParentChannelListener::OnStopRequest(nsIRequest* aRequest, + nsresult aStatusCode) { + MOZ_RELEASE_ASSERT(!mSuspendedForDiversion, + "Cannot call OnStopRequest if suspended for diversion!"); + + if (!mNextListener) return NS_ERROR_UNEXPECTED; + + LOG(("ParentChannelListener::OnStopRequest: [this=%p status=%" PRIu32 "]\n", + this, static_cast(aStatusCode))); + nsresult rv = mNextListener->OnStopRequest(aRequest, aStatusCode); + + mNextListener = nullptr; + return rv; +} + +//----------------------------------------------------------------------------- +// ParentChannelListener::nsIStreamListener +//----------------------------------------------------------------------------- + +NS_IMETHODIMP +ParentChannelListener::OnDataAvailable(nsIRequest* aRequest, + nsIInputStream* aInputStream, + uint64_t aOffset, uint32_t aCount) { + MOZ_RELEASE_ASSERT(!mSuspendedForDiversion, + "Cannot call OnDataAvailable if suspended for diversion!"); + + if (!mNextListener) return NS_ERROR_UNEXPECTED; + + LOG(("ParentChannelListener::OnDataAvailable [this=%p]\n", this)); + return mNextListener->OnDataAvailable(aRequest, aInputStream, aOffset, + aCount); +} + +//----------------------------------------------------------------------------- +// ParentChannelListener::nsIInterfaceRequestor +//----------------------------------------------------------------------------- + +NS_IMETHODIMP +ParentChannelListener::GetInterface(const nsIID& aIID, void** result) { + if (aIID.Equals(NS_GET_IID(nsINetworkInterceptController))) { + return QueryInterface(aIID, result); + } + + nsCOMPtr ir; + if (mNextListener && NS_SUCCEEDED(CallQueryInterface(mNextListener.get(), + getter_AddRefs(ir)))) { + return ir->GetInterface(aIID, result); + } + + if (aIID.Equals(NS_GET_IID(nsIAuthPrompt)) || + aIID.Equals(NS_GET_IID(nsIAuthPrompt2))) { + nsresult rv; + nsCOMPtr wwatch = + do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + return wwatch->GetPrompt(nullptr, aIID, reinterpret_cast(result)); + } + + return NS_NOINTERFACE; +} + +void ParentChannelListener::SetListenerAfterRedirect( + nsIStreamListener* aListener) { + mInterceptCanceled = false; + mNextListener = aListener; +} + +//----------------------------------------------------------------------------- +// ParentChannelListener::nsINetworkInterceptController +//----------------------------------------------------------------------------- + +NS_IMETHODIMP +ParentChannelListener::ShouldPrepareForIntercept(nsIURI* aURI, + nsIChannel* aChannel, + bool* aShouldIntercept) { + // If parent-side interception is enabled just forward to the real + // network controler. + if (mInterceptController) { + return mInterceptController->ShouldPrepareForIntercept(aURI, aChannel, + aShouldIntercept); + } + *aShouldIntercept = mShouldIntercept; + return NS_OK; +} + +class HeaderVisitor final : public nsIHttpHeaderVisitor { + nsCOMPtr mChannel; + ~HeaderVisitor() = default; + + public: + explicit HeaderVisitor(nsIInterceptedChannel* aChannel) + : mChannel(aChannel) {} + + NS_DECL_ISUPPORTS + + NS_IMETHOD VisitHeader(const nsACString& aHeader, + const nsACString& aValue) override { + mChannel->SynthesizeHeader(aHeader, aValue); + return NS_OK; + } +}; + +NS_IMPL_ISUPPORTS(HeaderVisitor, nsIHttpHeaderVisitor) + +class FinishSynthesizedResponse : public Runnable { + nsCOMPtr mChannel; + + public: + explicit FinishSynthesizedResponse(nsIInterceptedChannel* aChannel) + : Runnable("net::FinishSynthesizedResponse"), mChannel(aChannel) {} + + NS_IMETHOD Run() override { + // The URL passed as an argument here doesn't matter, since the child will + // receive a redirection notification as a result of this synthesized + // response. + mChannel->StartSynthesizedResponse(nullptr, nullptr, nullptr, + EmptyCString(), false); + mChannel->FinishSynthesizedResponse(); + return NS_OK; + } +}; + +NS_IMETHODIMP +ParentChannelListener::ChannelIntercepted(nsIInterceptedChannel* aChannel) { + // If parent-side interception is enabled just forward to the real + // network controler. + if (mInterceptController) { + return mInterceptController->ChannelIntercepted(aChannel); + } + + // Its possible for the child-side interception to complete and tear down + // the actor before we even get this parent-side interception notification. + // In this case we want to let the interception succeed, but then immediately + // cancel it. If we return an error code from here then it might get + // propagated back to the child process where the interception did not + // encounter an error. Therefore cancel the new channel asynchronously from a + // runnable. + if (mInterceptCanceled) { + nsCOMPtr r = NewRunnableMethod( + "ParentChannelListener::CancelInterception", aChannel, + &nsIInterceptedChannel::CancelInterception, NS_BINDING_ABORTED); + MOZ_ALWAYS_SUCCEEDS(SystemGroup::Dispatch(TaskCategory::Other, r.forget())); + return NS_OK; + } + + if (mShouldSuspendIntercept) { + mInterceptedChannel = aChannel; + return NS_OK; + } + + nsAutoCString statusText; + mSynthesizedResponseHead->StatusText(statusText); + aChannel->SynthesizeStatus(mSynthesizedResponseHead->Status(), statusText); + nsCOMPtr visitor = new HeaderVisitor(aChannel); + DebugOnly rv = mSynthesizedResponseHead->VisitHeaders( + visitor, nsHttpHeaderArray::eFilterResponse); + MOZ_ASSERT(NS_SUCCEEDED(rv)); + + nsCOMPtr event = new FinishSynthesizedResponse(aChannel); + NS_DispatchToCurrentThread(event); + + mSynthesizedResponseHead = nullptr; + + MOZ_ASSERT(mNextListener); + RefPtr channel = do_QueryObject(mNextListener); + MOZ_ASSERT(channel); + channel->ResponseSynthesized(); + + return NS_OK; +} + +//----------------------------------------------------------------------------- + +nsresult ParentChannelListener::SuspendForDiversion() { + if (NS_WARN_IF(mSuspendedForDiversion)) { + MOZ_ASSERT(!mSuspendedForDiversion, "Cannot SuspendForDiversion twice!"); + return NS_ERROR_UNEXPECTED; + } + + // While this is set, no OnStart/OnData/OnStop callbacks should be forwarded + // to mNextListener. + mSuspendedForDiversion = true; + + return NS_OK; +} + +nsresult ParentChannelListener::ResumeForDiversion() { + MOZ_RELEASE_ASSERT(mSuspendedForDiversion, "Must already be suspended!"); + + // Allow OnStart/OnData/OnStop callbacks to be forwarded to mNextListener. + mSuspendedForDiversion = false; + + return NS_OK; +} + +nsresult ParentChannelListener::DivertTo(nsIStreamListener* aListener) { + MOZ_ASSERT(aListener); + MOZ_RELEASE_ASSERT(mSuspendedForDiversion, "Must already be suspended!"); + + // Reset mInterceptCanceled back to false every time a new listener is set. + // We only want to cancel the interception if our current listener has + // signaled its cleaning up. + mInterceptCanceled = false; + + mNextListener = aListener; + + return ResumeForDiversion(); +} + +void ParentChannelListener::SetupInterception( + const nsHttpResponseHead& aResponseHead) { + mSynthesizedResponseHead = new nsHttpResponseHead(aResponseHead); + mShouldIntercept = true; +} + +void ParentChannelListener::SetupInterceptionAfterRedirect( + bool aShouldIntercept) { + mShouldIntercept = aShouldIntercept; + if (mShouldIntercept) { + // When an interception occurs, this channel should suspend all further + // activity. It will be torn down and recreated if necessary. + mShouldSuspendIntercept = true; + } +} + +void ParentChannelListener::ClearInterceptedChannel( + nsIStreamListener* aListener) { + // Only cancel the interception if this is from our current listener. We + // can get spurious calls here from other HttpChannelParent instances being + // destroyed asynchronously. + if (!SameCOMIdentity(mNextListener, aListener)) { + return; + } + if (mInterceptedChannel) { + mInterceptedChannel->CancelInterception(NS_ERROR_INTERCEPTION_FAILED); + mInterceptedChannel = nullptr; + } + // Note that channel interception has been canceled. If we got this before + // the interception even occured we will trigger the cancel later. + mInterceptCanceled = true; +} + +} // namespace net +} // namespace mozilla diff --git a/netwerk/protocol/http/HttpChannelParentListener.h b/netwerk/protocol/http/ParentChannelListener.h similarity index 66% rename from netwerk/protocol/http/HttpChannelParentListener.h rename to netwerk/protocol/http/ParentChannelListener.h index 0e4349d752b0..4b59fc080c04 100644 --- a/netwerk/protocol/http/HttpChannelParentListener.h +++ b/netwerk/protocol/http/ParentChannelListener.h @@ -5,24 +5,20 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#ifndef mozilla_net_HttpChannelCallbackWrapper_h -#define mozilla_net_HttpChannelCallbackWrapper_h +#ifndef mozilla_net_ParentChannelListener_h +#define mozilla_net_ParentChannelListener_h #include "nsIInterfaceRequestor.h" -#include "nsIChannelEventSink.h" -#include "nsIRedirectResultListener.h" #include "nsINetworkInterceptController.h" #include "nsIStreamListener.h" namespace mozilla { namespace net { -class HttpChannelParent; - -#define HTTP_CHANNEL_PARENT_LISTENER_IID \ +#define PARENT_CHANNEL_LISTENER \ { \ - 0xe409da52, 0xda76, 0x4eb7, { \ - 0xa7, 0xf4, 0x03, 0x3d, 0x88, 0xac, 0x87, 0x6d \ + 0xa4e2c10c, 0xceba, 0x457f, { \ + 0xa8, 0x0d, 0x78, 0x2b, 0x23, 0xba, 0xbd, 0x16 \ } \ } @@ -30,23 +26,19 @@ class HttpChannelParent; // works correctly on this object, as it's needed to compute a void* pointing to // the beginning of this object. -class HttpChannelParentListener final : public nsIInterfaceRequestor, - public nsIChannelEventSink, - public nsIRedirectResultListener, - public nsIStreamListener, - public nsINetworkInterceptController { +class ParentChannelListener final : public nsIInterfaceRequestor, + public nsIStreamListener, + public nsINetworkInterceptController { public: NS_DECL_ISUPPORTS NS_DECL_NSIINTERFACEREQUESTOR - NS_DECL_NSICHANNELEVENTSINK - NS_DECL_NSIREDIRECTRESULTLISTENER NS_DECL_NSIREQUESTOBSERVER NS_DECL_NSISTREAMLISTENER NS_DECL_NSINETWORKINTERCEPTCONTROLLER - NS_DECLARE_STATIC_IID_ACCESSOR(HTTP_CHANNEL_PARENT_LISTENER_IID) + NS_DECLARE_STATIC_IID_ACCESSOR(PARENT_CHANNEL_LISTENER) - explicit HttpChannelParentListener(HttpChannelParent* aInitialChannel); + explicit ParentChannelListener(nsIStreamListener* aListener); // For channel diversion from child to parent. MOZ_MUST_USE nsresult DivertTo(nsIStreamListener* aListener); @@ -56,12 +48,11 @@ class HttpChannelParentListener final : public nsIInterfaceRequestor, void SetupInterceptionAfterRedirect(bool aShouldIntercept); void ClearInterceptedChannel(nsIStreamListener* aListener); - nsresult TriggerCrossProcessRedirect(nsIChannel* oldChannel, - nsILoadInfo* aLoadInfo, - uint64_t aIdentifier); + // Called to set a new listener which replaces the old one after a redirect. + void SetListenerAfterRedirect(nsIStreamListener* aListener); private: - virtual ~HttpChannelParentListener(); + virtual ~ParentChannelListener(); // Private partner function to SuspendForDiversion. MOZ_MUST_USE nsresult ResumeForDiversion(); @@ -71,7 +62,6 @@ class HttpChannelParentListener final : public nsIInterfaceRequestor, // or some other listener that we have been diverted to via // nsIDivertableChannel. nsCOMPtr mNextListener; - uint32_t mRedirectChannelId; // When set, no OnStart/OnData/OnStop calls should be received. bool mSuspendedForDiversion; @@ -95,10 +85,9 @@ class HttpChannelParentListener final : public nsIInterfaceRequestor, nsCOMPtr mInterceptController; }; -NS_DEFINE_STATIC_IID_ACCESSOR(HttpChannelParentListener, - HTTP_CHANNEL_PARENT_LISTENER_IID) +NS_DEFINE_STATIC_IID_ACCESSOR(ParentChannelListener, PARENT_CHANNEL_LISTENER) } // namespace net } // namespace mozilla -#endif // mozilla_net_HttpChannelParent_h +#endif // mozilla_net_ParentChannelListener_h diff --git a/netwerk/protocol/http/TunnelUtils.cpp b/netwerk/protocol/http/TunnelUtils.cpp index 5338e67b099f..0fb3a8c32ed2 100644 --- a/netwerk/protocol/http/TunnelUtils.cpp +++ b/netwerk/protocol/http/TunnelUtils.cpp @@ -132,6 +132,20 @@ void TLSFilterTransaction::Close(nsresult aReason) { mTransaction->Close(aReason); mTransaction = nullptr; + if (!gHttpHandler->Bug1563695()) { + RefPtr baseTrans(do_QueryReferent(mWeakTrans)); + SpdyConnectTransaction* trans = + baseTrans ? baseTrans->QuerySpdyConnectTransaction() : nullptr; + + LOG(("TLSFilterTransaction::Close %p aReason=%" PRIx32 " trans=%p\n", this, + static_cast(aReason), trans)); + + if (trans) { + trans->Close(aReason); + trans = nullptr; + } + } + if (gHttpHandler->Bug1563538()) { if (NS_FAILED(aReason)) { mCloseReason = aReason; @@ -369,8 +383,28 @@ nsresult TLSFilterTransaction::WriteSegmentsAgain(nsAHttpSegmentWriter* aWriter, bool againBeforeWriteSegmentsCall = *again; mSegmentWriter = aWriter; + + /* + * Bug 1562315 replaced TLSFilterTransaction::WriteSegments with + * WriteSegmentsAgain and the call of WriteSegments on the associated + * transaction was replaced with WriteSegmentsAgain call. + * + * When TLSFilterTransaction::WriteSegmentsAgain was called from outside, it + * internally called WriteSegments (nsAHttpTransaction default impl) and did + * not modify the 'again' out flag. + * + * So, to disable the bug fix, we only need two things: + * - call mTransaction->WriteSegments + * - don't modify 'again' (which is an automatic outcome of step 1, this + * method doesn't touch it itself) + */ + nsresult rv = - mTransaction->WriteSegmentsAgain(this, aCount, outCountWritten, again); + gHttpHandler->Bug1562315() + ? mTransaction->WriteSegmentsAgain(this, aCount, outCountWritten, + again) + : mTransaction->WriteSegments(this, aCount, outCountWritten); + if (NS_SUCCEEDED(rv) && !(*outCountWritten)) { if (NS_FAILED(mFilterReadCode)) { // nsPipe turns failures into silent OK.. undo that! @@ -380,6 +414,7 @@ nsresult TLSFilterTransaction::WriteSegmentsAgain(nsAHttpSegmentWriter* aWriter, } } if (againBeforeWriteSegmentsCall && !*again) { + // This code can never be reached if bug1562315 pref is off. LOG( ("TLSFilterTransaction %p called trans->WriteSegments which dropped " "the 'again' flag", diff --git a/netwerk/protocol/http/moz.build b/netwerk/protocol/http/moz.build index 6668cc04dbf5..0943c455ddf1 100644 --- a/netwerk/protocol/http/moz.build +++ b/netwerk/protocol/http/moz.build @@ -82,7 +82,6 @@ UNIFIED_SOURCES += [ 'HttpBaseChannel.cpp', 'HttpChannelChild.cpp', 'HttpChannelParent.cpp', - 'HttpChannelParentListener.cpp', 'HttpInfo.cpp', 'HttpTrafficAnalyzer.cpp', 'InterceptedChannel.cpp', @@ -107,6 +106,7 @@ UNIFIED_SOURCES += [ 'nsServerTiming.cpp', 'NullHttpChannel.cpp', 'NullHttpTransaction.cpp', + 'ParentChannelListener.cpp', 'TunnelUtils.cpp', ] diff --git a/netwerk/protocol/http/nsHttpChannel.cpp b/netwerk/protocol/http/nsHttpChannel.cpp index e2336daae076..bf31dad56753 100644 --- a/netwerk/protocol/http/nsHttpChannel.cpp +++ b/netwerk/protocol/http/nsHttpChannel.cpp @@ -109,7 +109,7 @@ #include "nsMixedContentBlocker.h" #include "CacheStorageService.h" #include "HttpChannelParent.h" -#include "HttpChannelParentListener.h" +#include "ParentChannelListener.h" #include "InterceptedHttpChannel.h" #include "nsIBufferedStreams.h" #include "nsIFileStreams.h" @@ -7343,27 +7343,18 @@ nsresult nsHttpChannel::StartCrossProcessRedirect() { rv = CheckRedirectLimit(nsIChannelEventSink::REDIRECT_INTERNAL); NS_ENSURE_SUCCESS(rv, rv); - // We can't do QueryObject mCallbacks into HttpChannelParentListener, because - // the notification callbacks can be replaced with another object. - // Rather we do GetInterface for HttpChannelParent, which should always be - // there if the new callbacks properly forward to the original channel's - // callbacks, and get the listener from there using QueryObject. nsCOMPtr parentChannel; NS_QueryNotificationCallbacks(this, parentChannel); RefPtr httpParent = do_QueryObject(parentChannel); MOZ_ASSERT(httpParent); NS_ENSURE_TRUE(httpParent, NS_ERROR_UNEXPECTED); - RefPtr listener = httpParent->GetParentListener(); - MOZ_ASSERT(listener); - NS_ENSURE_TRUE(listener, NS_ERROR_UNEXPECTED); - nsCOMPtr redirectLoadInfo = CloneLoadInfoForRedirect(mURI, nsIChannelEventSink::REDIRECT_INTERNAL); redirectLoadInfo->SetResultPrincipalURI(mURI); - listener->TriggerCrossProcessRedirect(this, redirectLoadInfo, - mCrossProcessRedirectIdentifier); + httpParent->TriggerCrossProcessRedirect(this, redirectLoadInfo, + mCrossProcessRedirectIdentifier); // This will suspend the channel rv = WaitForRedirectCallback(); diff --git a/netwerk/protocol/http/nsHttpConnection.cpp b/netwerk/protocol/http/nsHttpConnection.cpp index eab268166cac..656dc8d12613 100644 --- a/netwerk/protocol/http/nsHttpConnection.cpp +++ b/netwerk/protocol/http/nsHttpConnection.cpp @@ -1812,7 +1812,7 @@ void nsHttpConnection::CloseTransaction(nsAHttpTransaction* trans, mSpdySession = nullptr; } - if (!mTransaction && mTLSFilter) { + if (!mTransaction && mTLSFilter && gHttpHandler->Bug1556491()) { // In case of a race when the transaction is being closed before the tunnel // is established we need to carry closing status on the proxied // transaction. diff --git a/netwerk/protocol/http/nsHttpHandler.cpp b/netwerk/protocol/http/nsHttpHandler.cpp index 9b2870ed912b..f54c72475899 100644 --- a/netwerk/protocol/http/nsHttpHandler.cpp +++ b/netwerk/protocol/http/nsHttpHandler.cpp @@ -275,6 +275,9 @@ nsHttpHandler::nsHttpHandler() mEnforceH1Framing(FRAMECHECK_BARELY), mDefaultHpackBuffer(4096), mBug1563538(true), + mBug1563695(true), + mBug1562315(true), + mBug1556491(true), mMaxHttpResponseHeaderSize(393216), mFocusedWindowTransactionRatio(0.9f), mSpeculativeConnectEnabled(false), @@ -1885,6 +1888,24 @@ void nsHttpHandler::PrefsChanged(const char* pref) { mBug1563538 = cVar; } } + if (PREF_CHANGED(HTTP_PREF("spdy.bug1563695"))) { + rv = Preferences::GetBool(HTTP_PREF("spdy.bug1563695"), &cVar); + if (NS_SUCCEEDED(rv)) { + mBug1563695 = cVar; + } + } + if (PREF_CHANGED(HTTP_PREF("spdy.bug1562315"))) { + rv = Preferences::GetBool(HTTP_PREF("spdy.bug1562315"), &cVar); + if (NS_SUCCEEDED(rv)) { + mBug1562315 = cVar; + } + } + if (PREF_CHANGED(HTTP_PREF("spdy.bug1556491"))) { + rv = Preferences::GetBool(HTTP_PREF("spdy.bug1556491"), &cVar); + if (NS_SUCCEEDED(rv)) { + mBug1556491 = cVar; + } + } // Enable HTTP response timeout if TCP Keepalives are disabled. mResponseTimeoutEnabled = diff --git a/netwerk/protocol/http/nsHttpHandler.h b/netwerk/protocol/http/nsHttpHandler.h index b413aaae94e3..88b0ec82f1e7 100644 --- a/netwerk/protocol/http/nsHttpHandler.h +++ b/netwerk/protocol/http/nsHttpHandler.h @@ -430,6 +430,9 @@ class nsHttpHandler final : public nsIHttpProtocolHandler, uint32_t DefaultHpackBuffer() const { return mDefaultHpackBuffer; } bool Bug1563538() const { return mBug1563538; } + bool Bug1563695() const { return mBug1563695; } + bool Bug1562315() const { return mBug1562315; } + bool Bug1556491() const { return mBug1556491; } uint32_t MaxHttpResponseHeaderSize() const { return mMaxHttpResponseHeaderSize; @@ -675,6 +678,9 @@ class nsHttpHandler final : public nsIHttpProtocolHandler, // Pref for the whole fix that bug provides Atomic mBug1563538; + Atomic mBug1563695; + Atomic mBug1562315; + Atomic mBug1556491; // The max size (in bytes) for received Http response header. uint32_t mMaxHttpResponseHeaderSize; diff --git a/testing/web-platform/meta/mediacapture-streams/MediaStreamTrack-MediaElement-disabled-video-is-black.https.html.ini b/testing/web-platform/meta/mediacapture-streams/MediaStreamTrack-MediaElement-disabled-video-is-black.https.html.ini deleted file mode 100644 index 22bb650b04a0..000000000000 --- a/testing/web-platform/meta/mediacapture-streams/MediaStreamTrack-MediaElement-disabled-video-is-black.https.html.ini +++ /dev/null @@ -1,7 +0,0 @@ -[MediaStreamTrack-MediaElement-disabled-video-is-black.https.html] - [Tests that a disabled video track in a MediaStream is rendered as blackness] - expected: FAIL - - [A disabled video track is rendered as blackness] - expected: FAIL - diff --git a/testing/web-platform/meta/webaudio/idlharness.https.window.js.ini b/testing/web-platform/meta/webaudio/idlharness.https.window.js.ini index 07163f5d54ec..c3e828c16193 100644 --- a/testing/web-platform/meta/webaudio/idlharness.https.window.js.ini +++ b/testing/web-platform/meta/webaudio/idlharness.https.window.js.ini @@ -14,15 +14,9 @@ [AudioListener interface: attribute forwardX] expected: FAIL - [MediaStreamAudioSourceNode interface: attribute mediaStream] - expected: FAIL - [AudioParam interface: calling cancelAndHoldAtTime(double) on new AudioBufferSourceNode(context).playbackRate with too few arguments must throw TypeError] expected: FAIL - [AudioContext interface: context must inherit property "getOutputTimestamp()" with the proper type] - expected: FAIL - [AudioListener interface: context.listener must inherit property "forwardX" with the proper type] expected: FAIL @@ -41,12 +35,6 @@ [AudioListener interface: context.listener must inherit property "positionY" with the proper type] expected: FAIL - [MediaElementAudioSourceNode interface: new MediaElementAudioSourceNode(context, {mediaElement: new Audio}) must inherit property "mediaElement" with the proper type] - expected: FAIL - - [AudioContext interface: operation getOutputTimestamp()] - expected: FAIL - [Stringification of new AudioProcessingEvent('', {\n playbackTime: 0, inputBuffer: buffer, outputBuffer: buffer\n })] expected: FAIL @@ -74,12 +62,6 @@ [AudioListener interface: context.listener must inherit property "forwardY" with the proper type] expected: FAIL - [AudioContext interface: context must inherit property "baseLatency" with the proper type] - expected: FAIL - - [MediaElementAudioSourceNode interface: attribute mediaElement] - expected: FAIL - [AudioListener interface: context.listener must inherit property "positionX" with the proper type] expected: FAIL @@ -98,21 +80,12 @@ [AudioParamMap must be primary interface of worklet_node.parameters] expected: FAIL - [AudioContext interface: context must inherit property "outputLatency" with the proper type] - expected: FAIL - [OfflineAudioContext interface: operation suspend(double)] expected: FAIL - [AudioContext interface: attribute baseLatency] - expected: FAIL - [AudioParam interface: new AudioBufferSourceNode(context).playbackRate must inherit property "cancelAndHoldAtTime(double)" with the proper type] expected: FAIL - [AudioContext interface: attribute outputLatency] - expected: FAIL - [AudioListener interface: attribute upX] expected: FAIL diff --git a/testing/web-platform/meta/webaudio/the-audio-api/the-audiocontext-interface/audiocontext-getoutputtimestamp.html.ini b/testing/web-platform/meta/webaudio/the-audio-api/the-audiocontext-interface/audiocontext-getoutputtimestamp.html.ini deleted file mode 100644 index abdb861f9365..000000000000 --- a/testing/web-platform/meta/webaudio/the-audio-api/the-audiocontext-interface/audiocontext-getoutputtimestamp.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[audiocontext-getoutputtimestamp.html] - expected: ERROR diff --git a/testing/web-platform/meta/webaudio/the-audio-api/the-audiocontext-interface/audiocontextoptions.html.ini b/testing/web-platform/meta/webaudio/the-audio-api/the-audiocontext-interface/audiocontextoptions.html.ini index ceba861957ab..40daf64c203d 100644 --- a/testing/web-platform/meta/webaudio/the-audio-api/the-audiocontext-interface/audiocontextoptions.html.ini +++ b/testing/web-platform/meta/webaudio/the-audio-api/the-audiocontext-interface/audiocontextoptions.html.ini @@ -1,16 +1,4 @@ [audiocontextoptions.html] - [X default baseLatency is not greater than 0. Got undefined.] - expected: FAIL - - [X balanced baseLatency is not greater than or equal to undefined. Got undefined.] - expected: FAIL - - [X playback baseLatency is not greater than or equal to undefined. Got undefined.] - expected: FAIL - - [< [test-audiocontextoptions-latencyHint-basic\] 3 out of 9 assertions were failed.] - expected: FAIL - [X double-constructor baseLatency small is not less than or equal to undefined. Got undefined.] expected: FAIL @@ -35,3 +23,9 @@ [# AUDIT TASK RUNNER FINISHED: 2 out of 3 tasks were failed.] expected: FAIL + [< [test-audiocontextoptions-latencyHint-double\] 1 out of 10 assertions were failed.] + expected: FAIL + + [# AUDIT TASK RUNNER FINISHED: 1 out of 3 tasks were failed.] + expected: FAIL + diff --git a/testing/web-platform/moz.build b/testing/web-platform/moz.build index e81f9545b462..51760b20a85b 100644 --- a/testing/web-platform/moz.build +++ b/testing/web-platform/moz.build @@ -302,7 +302,6 @@ with Files("tests/fullscreen/**"): with Files("tests/gamepad/**"): BUG_COMPONENT = ("Core", "DOM: Device Interfaces") -# Bug 1359076 - Deleting this feature due to security with Files("tests/geolocation-API/**"): BUG_COMPONENT = ("Core", "Geolocation") diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/manifestupdate.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/manifestupdate.py index 82ba88dfb050..fbe042a8d37e 100644 --- a/testing/web-platform/tests/tools/wptrunner/wptrunner/manifestupdate.py +++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/manifestupdate.py @@ -411,7 +411,9 @@ class PropertyUpdate(object): # If all the values match remove all conditionals # This handles the case where we update a number of existing conditions and they # all end up looking like the post-update default. - new_default = conditions[-1][1] if conditions[-1][0] is None else self.default_value + new_default = self.default_value + if conditions and conditions[-1][0] is None: + new_default = conditions[-1][1] if all(condition[1] == new_default for condition in conditions): conditions = [(None, new_default)] diff --git a/testing/web-platform/tests/webaudio/the-audio-api/the-audiocontext-interface/audiocontextoptions.html b/testing/web-platform/tests/webaudio/the-audio-api/the-audiocontext-interface/audiocontextoptions.html index bee1aa835bf6..b556e31b5e0d 100644 --- a/testing/web-platform/tests/webaudio/the-audio-api/the-audiocontext-interface/audiocontextoptions.html +++ b/testing/web-platform/tests/webaudio/the-audio-api/the-audiocontext-interface/audiocontextoptions.html @@ -35,7 +35,7 @@ `context.sampleRate (${context.sampleRate} Hz)`).beGreaterThan(0); defaultLatency = context.baseLatency; - should(defaultLatency, 'default baseLatency').beGreaterThan(0); + should(defaultLatency, 'default baseLatency').beGreaterThanOrEqualTo(0); // Verify that an AudioContext can be created with the expected // latency types. @@ -130,7 +130,7 @@ should(context1.baseLatency, 'high latency context baseLatency') .beEqualTo(context2.baseLatency); should(context1.baseLatency, 'high latency context baseLatency') - .beGreaterThan(interactiveLatency); + .beGreaterThanOrEqualTo(interactiveLatency); closingPromises.push(context1.close()); closingPromises.push(context2.close()); diff --git a/third_party/rust/euclid/.cargo-checksum.json b/third_party/rust/euclid/.cargo-checksum.json index 8f7d8096e5ed..3dcaa175150e 100644 --- a/third_party/rust/euclid/.cargo-checksum.json +++ b/third_party/rust/euclid/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"COPYRIGHT":"ec82b96487e9e778ee610c7ab245162464782cfa1f555c2299333f8dbe5c036a","Cargo.toml":"4c50cb6cf03b2ab58cf9c017fdeee3f3d918b6143adeb529910f329bb07e7fd3","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"62065228e42caebca7e7d7db1204cbb867033de5982ca4009928915e4095f3a3","README.md":"625bec69c76ce5423fdd05cfe46922b2680ec517f97c5854ce34798d1d8a9541","src/approxeq.rs":"6594377e8f6c20f88f628520d8de9b9a59c5892a0ee9a6ccd13c8400c1499911","src/homogen.rs":"7b02aa671fffcb554557ad790f598bd5d7440dc1aa4a6d1c5a97d8bc3c8f64d6","src/length.rs":"3171315822707728b1bfbdd04a4190ffb7206b4bfc59e9dd072bb2caa05ff292","src/lib.rs":"e8b1317127ec281fd42318f2c470558c2ecbb2e1459cebd4f9c63a2af807eb3d","src/macros.rs":"3b475e84d00cceee6c7e96e9f2c97ba15d8dc7f4094efb82c5ed10bd60d86a64","src/num.rs":"4439479fad5729073e0bfe0b96b547672a237430d48e564519759b9550baa033","src/point.rs":"689a8348428d12f6c5262965c505395bde37b4b1776369d93e93d73406d5344b","src/rect.rs":"ae16bb9ccb95cf329439d0ea4eb4c3821c4cd769cce4a544904b65d7e4af04b7","src/rotation.rs":"3d765a8e8e8c7181cc10d39be617779a8676d2611b408c69c841c3a10ce78a47","src/scale.rs":"fc07bcf47f3a1215023c830059f0d270e570cbd37fe8c367ef4a47b191f4ae3e","src/side_offsets.rs":"b79d43cca4c2e9fac7482a95661f72cb3ed51008f1d3e0c3f4fe608c68ef3658","src/size.rs":"49088bf3bf0e1ce740c1fe92761c18a43a6287d1d81a945bc92b21af63ef3416","src/transform2d.rs":"641acc1c9de9368bdbe0bb64b5ba4c1069ebeda6d6ad31463c81bdf85d678043","src/transform3d.rs":"c47dda0759629c1a836861fabf65e889001cf2d5ab59258544c1c04167cd7a67","src/translation.rs":"9787de1bccdd402774ba9a5bc55ec6d4b2ee36e0a146baecee417ee9cc753db5","src/trig.rs":"97a263c4f178b0332501659ca8143f9f637a0755aca189dd31ac551bcd4cb73c","src/vector.rs":"d57493649da9d8a728dcba49bb80c579a4d2bf6f3557dd4b4c770cfcef6ee395"},"package":"d1a7698bdda3d7444a79d33bdc96e8b518d44ea3ff101d8492a6ca1207b886ea"} \ No newline at end of file +{"files":{"COPYRIGHT":"ec82b96487e9e778ee610c7ab245162464782cfa1f555c2299333f8dbe5c036a","Cargo.toml":"6ed8512d0e0c349a53eddd15a806e67e84359c1071d7d4a404f513cca091d5f5","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"62065228e42caebca7e7d7db1204cbb867033de5982ca4009928915e4095f3a3","README.md":"625bec69c76ce5423fdd05cfe46922b2680ec517f97c5854ce34798d1d8a9541","src/approxeq.rs":"6594377e8f6c20f88f628520d8de9b9a59c5892a0ee9a6ccd13c8400c1499911","src/approxord.rs":"087e0a8d24b8a9bed4c1cc571eec5e50cc7afa184c6ac4961c7409a69456ec7b","src/box2d.rs":"5e2d634cf2181fd9f556a600d4339cb6a098341ac71f72e0bc7521b3b3fb2f19","src/box3d.rs":"8d87e7e487d0772462cc2c6033bcd05f4fee44127c4aa0a4d72407ac6a02e03b","src/homogen.rs":"7b02aa671fffcb554557ad790f598bd5d7440dc1aa4a6d1c5a97d8bc3c8f64d6","src/length.rs":"3171315822707728b1bfbdd04a4190ffb7206b4bfc59e9dd072bb2caa05ff292","src/lib.rs":"e8bbae14e1b284fba3529af44396e488cbc48f8b3d20ddb26da5919d9c02601b","src/macros.rs":"3b475e84d00cceee6c7e96e9f2c97ba15d8dc7f4094efb82c5ed10bd60d86a64","src/num.rs":"4439479fad5729073e0bfe0b96b547672a237430d48e564519759b9550baa033","src/point.rs":"b51cf9b7713d9a48452d833cfbc97bb95e0c2202c4f77cadd02633ce80a600df","src/rect.rs":"2e4036f3f7e2ca62e6f9a52787ca9b9765b401a11cf1e70dff6c81142bdd91ed","src/rigid.rs":"e50a5df42add328ed5164e1954592406ce6d8f564beb4ca375c5cca920e93fbc","src/rotation.rs":"3d1a934a7c59bd7ca8501d17d463d5af41fb529c5aa8fe8c3bb8a2b236d4abc0","src/scale.rs":"fc07bcf47f3a1215023c830059f0d270e570cbd37fe8c367ef4a47b191f4ae3e","src/side_offsets.rs":"d9b1463672e1204bf8e7dd6fe0f7601eb75b6690ec6eb18debcee07f5ca92ee3","src/size.rs":"c4e38966c280ab5b4963961eebdbb12e0f448aea624cbe760b02ca2221a004e5","src/transform2d.rs":"7657d447993dc820e404ea9fbde6cb2900d874d4f5c735e85c6225c9f3b4110d","src/transform3d.rs":"af3d909ee103d02fec5f59599055cc3cee5217975b030e0089e1f1d99ad5139e","src/translation.rs":"b21d1d81a34b80d3285d42f33e8039fdb787749f017d2a7a2295d036c2f50548","src/trig.rs":"97a263c4f178b0332501659ca8143f9f637a0755aca189dd31ac551bcd4cb73c","src/vector.rs":"dcd0904757ed0e7d12da1c612746da3e32c56e2248ec13041d1f3786811af51c"},"package":"596b99621b9477e7a5f94d2d8dd13a9c5c302ac358b822c67a42b6f1054450e1"} \ No newline at end of file diff --git a/third_party/rust/euclid/Cargo.toml b/third_party/rust/euclid/Cargo.toml index 6000b073280b..7fdcf2ced83a 100644 --- a/third_party/rust/euclid/Cargo.toml +++ b/third_party/rust/euclid/Cargo.toml @@ -3,7 +3,7 @@ # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g. crates.io) dependencies +# to registry (e.g., crates.io) dependencies # # If you believe there's an error in this file please file an # issue against the rust-lang/cargo repository. If you're @@ -12,7 +12,7 @@ [package] name = "euclid" -version = "0.19.5" +version = "0.19.9" authors = ["The Servo Project Developers"] description = "Geometry primitives" documentation = "https://docs.rs/euclid/" diff --git a/third_party/rust/euclid/src/approxord.rs b/third_party/rust/euclid/src/approxord.rs new file mode 100644 index 000000000000..9654f2aba2f3 --- /dev/null +++ b/third_party/rust/euclid/src/approxord.rs @@ -0,0 +1,43 @@ +// Copyright 2013 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/// Utilities for testing approximate ordering - especially true for +/// floating point types, where NaN's cannot be ordered. +pub fn min(x: T, y: T) -> T { + if x <= y { + x + } else { + y + } +} + +pub fn max(x: T, y: T) -> T { + if x >= y { + x + } else { + y + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_min() { + assert!(min(0u32, 1u32) == 0u32); + assert!(min(-1.0f32, 0.0f32) == -1.0f32); + } + + #[test] + fn test_max() { + assert!(max(0u32, 1u32) == 1u32); + assert!(max(-1.0f32, 0.0f32) == 0.0f32); + } +} diff --git a/third_party/rust/euclid/src/box2d.rs b/third_party/rust/euclid/src/box2d.rs new file mode 100644 index 000000000000..19642a5f6b24 --- /dev/null +++ b/third_party/rust/euclid/src/box2d.rs @@ -0,0 +1,793 @@ +// Copyright 2013 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use super::UnknownUnit; +use scale::TypedScale; +use num::*; +use rect::TypedRect; +use point::{point2, TypedPoint2D}; +use vector::{vec2, TypedVector2D}; +use side_offsets::TypedSideOffsets2D; +use size::TypedSize2D; +use approxord::{min, max}; + +use num_traits::NumCast; +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; + +use core::borrow::Borrow; +use core::cmp::PartialOrd; +use core::fmt; +use core::hash::{Hash, Hasher}; +use core::ops::{Add, Div, Mul, Sub}; + + +/// An axis aligned rectangle represented by its minimum and maximum coordinates. +#[repr(C)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "serde", serde(bound(serialize = "T: Serialize", deserialize = "T: Deserialize<'de>")))] +pub struct TypedBox2D { + pub min: TypedPoint2D, + pub max: TypedPoint2D, +} + +/// The default box 2d type with no unit. +pub type Box2D = TypedBox2D; + +impl Hash for TypedBox2D { + fn hash(&self, h: &mut H) { + self.min.hash(h); + self.max.hash(h); + } +} + +impl Copy for TypedBox2D {} + +impl Clone for TypedBox2D { + fn clone(&self) -> Self { + *self + } +} + +impl PartialEq> for TypedBox2D { + fn eq(&self, other: &Self) -> bool { + self.min.eq(&other.min) && self.max.eq(&other.max) + } +} + +impl Eq for TypedBox2D {} + +impl fmt::Debug for TypedBox2D { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "TypedBox2D({:?}, {:?})", self.min, self.max) + } +} + +impl fmt::Display for TypedBox2D { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "Box2D({}, {})", self.min, self.max) + } +} + +impl TypedBox2D { + /// Constructor. + pub fn new(min: TypedPoint2D, max: TypedPoint2D) -> Self { + TypedBox2D { + min, + max, + } + } +} + +impl TypedBox2D +where + T: Copy + Zero + PartialOrd, +{ + /// Creates a Box2D of the given size, at offset zero. + #[inline] + pub fn from_size(size: TypedSize2D) -> Self { + let zero = TypedPoint2D::zero(); + let point = size.to_vector().to_point(); + TypedBox2D::from_points(&[zero, point]) + } +} + +impl TypedBox2D +where + T: Copy + PartialOrd, +{ + /// Returns true if the box has a negative area. + /// + /// The common interpretation for a negative box is to consider it empty. It can be obtained + /// by calculating the intersection of two boxes that do not intersect. + #[inline] + pub fn is_negative(&self) -> bool { + self.max.x < self.min.x || self.max.y < self.min.y + } + + /// Returns true if the size is zero or negative. + #[inline] + pub fn is_empty_or_negative(&self) -> bool { + self.max.x <= self.min.x || self.max.y <= self.min.y + } + + /// Returns true if the two boxes intersect. + #[inline] + pub fn intersects(&self, other: &Self) -> bool { + self.min.x < other.max.x + && self.max.x > other.min.x + && self.min.y < other.max.y + && self.max.y > other.min.y + } + + /// Computes the intersection of two boxes. + /// + /// The result is a negative box if the boxes do not intersect. + #[inline] + pub fn intersection(&self, other: &Self) -> Self { + TypedBox2D { + min: point2( + max(self.min.x, other.min.x), + max(self.min.y, other.min.y), + ), + max: point2( + min(self.max.x, other.max.x), + min(self.max.y, other.max.y), + ) + } + } + + /// Computes the intersection of two boxes, returning `None` if the boxes do not intersect. + #[inline] + pub fn try_intersection(&self, other: &Self) -> Option { + let intersection = self.intersection(other); + + if intersection.is_negative() { + return None; + } + + Some(intersection) + } +} + +impl TypedBox2D +where + T: Copy + Add, +{ + /// Returns the same box, translated by a vector. + #[inline] + pub fn translate(&self, by: &TypedVector2D) -> Self { + Self::new(self.min + *by, self.max + *by) + } +} + +impl TypedBox2D +where + T: Copy + PartialOrd + Zero, +{ + /// Returns true if this box contains the point. Points are considered + /// in the box if they are on the front, left or top faces, but outside if they + /// are on the back, right or bottom faces. + #[inline] + pub fn contains(&self, p: &TypedPoint2D) -> bool { + self.min.x <= p.x && p.x < self.max.x + && self.min.y <= p.y && p.y < self.max.y + } +} + +impl TypedBox2D +where + T: Copy + PartialOrd + Zero + Sub, +{ + /// Returns true if this box contains the interior of the other box. Always + /// returns true if other is empty, and always returns false if other is + /// nonempty but this box is empty. + #[inline] + pub fn contains_box(&self, other: &Self) -> bool { + other.is_empty_or_negative() + || (self.min.x <= other.min.x && other.max.x <= self.max.x + && self.min.y <= other.min.y && other.max.y <= self.max.y) + } +} + +impl TypedBox2D +where + T: Copy + Sub, +{ + #[inline] + pub fn size(&self)-> TypedSize2D { + (self.max - self.min).to_size() + } + + #[inline] + pub fn to_rect(&self) -> TypedRect { + TypedRect { + origin: self.min, + size: self.size(), + } + } +} + +impl TypedBox2D +where + T: Copy + PartialEq + Add + Sub, +{ + /// Inflates the box by the specified sizes on each side respectively. + #[inline] + #[cfg_attr(feature = "unstable", must_use)] + pub fn inflate(&self, width: T, height: T) -> Self { + TypedBox2D { + min: point2(self.min.x - width, self.min.y - height), + max: point2(self.max.x + width, self.max.y + height), + } + } +} + +impl TypedBox2D +where + T: Copy + Zero + PartialOrd + Add + Sub, +{ + /// Calculate the size and position of an inner box. + /// + /// Subtracts the side offsets from all sides. The horizontal, vertical + /// and applicate offsets must not be larger than the original side length. + pub fn inner_box(&self, offsets: TypedSideOffsets2D) -> Self { + TypedBox2D { + min: self.min + vec2(offsets.left, offsets.top), + max: self.max - vec2(offsets.right, offsets.bottom), + } + } + + /// Calculate the b and position of an outer box. + /// + /// Add the offsets to all sides. The expanded box is returned. + pub fn outer_box(&self, offsets: TypedSideOffsets2D) -> Self { + TypedBox2D { + min: self.min - vec2(offsets.left, offsets.top), + max: self.max + vec2(offsets.right, offsets.bottom), + } + } +} + + +impl TypedBox2D +where + T: Copy + Zero + PartialOrd, +{ + /// Returns the smallest box containing all of the provided points. + pub fn from_points(points: I) -> Self + where + I: IntoIterator, + I::Item: Borrow>, + { + let mut points = points.into_iter(); + + // Need at least 2 different points for a valid box (ie: volume > 0). + let (mut min_x, mut min_y) = match points.next() { + Some(first) => (first.borrow().x, first.borrow().y), + None => return TypedBox2D::zero(), + }; + let (mut max_x, mut max_y) = (min_x, min_y); + + { + let mut assign_min_max = |point: I::Item| { + let p = point.borrow(); + if p.x < min_x { + min_x = p.x + } + if p.x > max_x { + max_x = p.x + } + if p.y < min_y { + min_y = p.y + } + if p.y > max_y { + max_y = p.y + } + }; + + match points.next() { + Some(second) => assign_min_max(second), + None => return TypedBox2D::zero(), + } + + for point in points { + assign_min_max(point); + } + } + + TypedBox2D { + min: point2(min_x, min_y), + max: point2(max_x, max_y), + } + } +} + +impl TypedBox2D +where + T: Copy + One + Add + Sub + Mul, +{ + /// Linearly interpolate between this box and another box. + /// + /// `t` is expected to be between zero and one. + #[inline] + pub fn lerp(&self, other: Self, t: T) -> Self { + Self::new( + self.min.lerp(other.min, t), + self.max.lerp(other.max, t), + ) + } +} + +impl TypedBox2D +where + T: Copy + One + Add + Div, +{ + pub fn center(&self) -> TypedPoint2D { + let two = T::one() + T::one(); + (self.min + self.max.to_vector()) / two + } +} + +impl TypedBox2D +where + T: Copy + PartialOrd, +{ + #[inline] + pub fn union(&self, other: &Self) -> Self { + TypedBox2D { + min: point2( + min(self.min.x, other.min.x), + min(self.min.y, other.min.y), + ), + max: point2( + max(self.max.x, other.max.x), + max(self.max.y, other.max.y), + ), + } + } +} + +impl TypedBox2D +where + T: Copy, +{ + #[inline] + pub fn scale(&self, x: S, y: S) -> Self + where + T: Mul + { + TypedBox2D { + min: point2(self.min.x * x, self.min.y * y), + max: point2(self.max.x * x, self.max.y * y), + } + } +} + +impl TypedBox2D +where + T: Copy + Mul + Sub, +{ + #[inline] + pub fn area(&self) -> T { + let size = self.size(); + size.width * size.height + } +} + +impl TypedBox2D +where + T: Copy + Zero, +{ + /// Constructor, setting all sides to zero. + pub fn zero() -> Self { + TypedBox2D::new(TypedPoint2D::zero(), TypedPoint2D::zero()) + } +} + +impl TypedBox2D +where + T: PartialEq, +{ + /// Returns true if the size is zero. + #[inline] + pub fn is_empty(&self) -> bool { + self.min.x == self.max.x || self.min.y == self.max.y + } +} + +impl Mul for TypedBox2D +where + T: Copy + Mul, +{ + type Output = Self; + #[inline] + fn mul(self, scale: T) -> Self { + TypedBox2D::new(self.min * scale, self.max * scale) + } +} + +impl Div for TypedBox2D +where + T: Copy + Div, +{ + type Output = Self; + #[inline] + fn div(self, scale: T) -> Self { + TypedBox2D::new(self.min / scale, self.max / scale) + } +} + +impl Mul> for TypedBox2D +where + T: Copy + Mul, +{ + type Output = TypedBox2D; + #[inline] + fn mul(self, scale: TypedScale) -> TypedBox2D { + TypedBox2D::new(self.min * scale, self.max * scale) + } +} + +impl Div> for TypedBox2D +where + T: Copy + Div, +{ + type Output = TypedBox2D; + #[inline] + fn div(self, scale: TypedScale) -> TypedBox2D { + TypedBox2D::new(self.min / scale, self.max / scale) + } +} + +impl TypedBox2D +where + T: Copy, +{ + /// Drop the units, preserving only the numeric value. + pub fn to_untyped(&self) -> Box2D { + TypedBox2D::new(self.min.to_untyped(), self.max.to_untyped()) + } + + /// Tag a unitless value with units. + pub fn from_untyped(c: &Box2D) -> TypedBox2D { + TypedBox2D::new( + TypedPoint2D::from_untyped(&c.min), + TypedPoint2D::from_untyped(&c.max), + ) + } +} + +impl TypedBox2D +where + T0: NumCast + Copy, +{ + /// Cast from one numeric representation to another, preserving the units. + /// + /// When casting from floating point to integer coordinates, the decimals are truncated + /// as one would expect from a simple cast, but this behavior does not always make sense + /// geometrically. Consider using round(), round_in or round_out() before casting. + pub fn cast(&self) -> TypedBox2D { + TypedBox2D::new( + self.min.cast(), + self.max.cast(), + ) + } + + /// Fallible cast from one numeric representation to another, preserving the units. + /// + /// When casting from floating point to integer coordinates, the decimals are truncated + /// as one would expect from a simple cast, but this behavior does not always make sense + /// geometrically. Consider using round(), round_in or round_out() before casting. + pub fn try_cast(&self) -> Option> { + match (self.min.try_cast(), self.max.try_cast()) { + (Some(a), Some(b)) => Some(TypedBox2D::new(a, b)), + _ => None, + } + } +} + +impl TypedBox2D +where + T: Round, +{ + /// Return a box with edges rounded to integer coordinates, such that + /// the returned box has the same set of pixel centers as the original + /// one. + /// Values equal to 0.5 round up. + /// Suitable for most places where integral device coordinates + /// are needed, but note that any translation should be applied first to + /// avoid pixel rounding errors. + /// Note that this is *not* rounding to nearest integer if the values are negative. + /// They are always rounding as floor(n + 0.5). + #[cfg_attr(feature = "unstable", must_use)] + pub fn round(&self) -> Self { + TypedBox2D::new(self.min.round(), self.max.round()) + } +} + +impl TypedBox2D +where + T: Floor + Ceil, +{ + /// Return a box with faces/edges rounded to integer coordinates, such that + /// the original box contains the resulting box. + #[cfg_attr(feature = "unstable", must_use)] + pub fn round_in(&self) -> Self { + let min = self.min.ceil(); + let max = self.max.floor(); + TypedBox2D { min, max } + } + + /// Return a box with faces/edges rounded to integer coordinates, such that + /// the original box is contained in the resulting box. + #[cfg_attr(feature = "unstable", must_use)] + pub fn round_out(&self) -> Self { + let min = self.min.floor(); + let max = self.max.ceil(); + TypedBox2D { min, max } + } +} + +// Convenience functions for common casts +impl TypedBox2D { + /// Cast into an `f32` box. + pub fn to_f32(&self) -> TypedBox2D { + self.cast() + } + + /// Cast into an `f64` box. + pub fn to_f64(&self) -> TypedBox2D { + self.cast() + } + + /// Cast into an `usize` box, truncating decimals if any. + /// + /// When casting from floating point boxes, it is worth considering whether + /// to `round()`, `round_in()` or `round_out()` before the cast in order to + /// obtain the desired conversion behavior. + pub fn to_usize(&self) -> TypedBox2D { + self.cast() + } + + /// Cast into an `u32` box, truncating decimals if any. + /// + /// When casting from floating point boxes, it is worth considering whether + /// to `round()`, `round_in()` or `round_out()` before the cast in order to + /// obtain the desired conversion behavior. + pub fn to_u32(&self) -> TypedBox2D { + self.cast() + } + + /// Cast into an `i32` box, truncating decimals if any. + /// + /// When casting from floating point boxes, it is worth considering whether + /// to `round()`, `round_in()` or `round_out()` before the cast in order to + /// obtain the desired conversion behavior. + pub fn to_i32(&self) -> TypedBox2D { + self.cast() + } + + /// Cast into an `i64` box, truncating decimals if any. + /// + /// When casting from floating point boxes, it is worth considering whether + /// to `round()`, `round_in()` or `round_out()` before the cast in order to + /// obtain the desired conversion behavior. + pub fn to_i64(&self) -> TypedBox2D { + self.cast() + } +} + +impl From> for TypedBox2D +where + T: Copy + Zero + PartialOrd, +{ + fn from(b: TypedSize2D) -> Self { + Self::from_size(b) + } +} + +#[cfg(test)] +mod tests { + use side_offsets::SideOffsets2D; + use size::size2; + use point::Point2D; + use super::*; + + #[test] + fn test_size() { + let b = Box2D::new(point2(-10.0, -10.0), point2(10.0, 10.0)); + assert_eq!(b.size().width, 20.0); + assert_eq!(b.size().height, 20.0); + } + + #[test] + fn test_center() { + let b = Box2D::new(point2(-10.0, -10.0), point2(10.0, 10.0)); + assert_eq!(b.center(), Point2D::zero()); + } + + #[test] + fn test_area() { + let b = Box2D::new(point2(-10.0, -10.0), point2(10.0, 10.0)); + assert_eq!(b.area(), 400.0); + } + + #[test] + fn test_from_points() { + let b = Box2D::from_points(&[point2(50.0, 160.0), point2(100.0, 25.0)]); + assert_eq!(b.min, point2(50.0, 25.0)); + assert_eq!(b.max, point2(100.0, 160.0)); + } + + #[test] + fn test_round_in() { + let b = Box2D::from_points(&[point2(-25.5, -40.4), point2(60.3, 36.5)]).round_in(); + assert_eq!(b.min.x, -25.0); + assert_eq!(b.min.y, -40.0); + assert_eq!(b.max.x, 60.0); + assert_eq!(b.max.y, 36.0); + } + + #[test] + fn test_round_out() { + let b = Box2D::from_points(&[point2(-25.5, -40.4), point2(60.3, 36.5)]).round_out(); + assert_eq!(b.min.x,-26.0); + assert_eq!(b.min.y, -41.0); + assert_eq!(b.max.x, 61.0); + assert_eq!(b.max.y, 37.0); + } + + #[test] + fn test_round() { + let b = Box2D::from_points(&[point2(-25.5, -40.4), point2(60.3, 36.5)]).round(); + assert_eq!(b.min.x,-26.0); + assert_eq!(b.min.y, -40.0); + assert_eq!(b.max.x, 60.0); + assert_eq!(b.max.y, 37.0); + } + + #[test] + fn test_from_size() { + let b = Box2D::from_size(size2(30.0, 40.0)); + assert!(b.min == Point2D::zero()); + assert!(b.size().width == 30.0); + assert!(b.size().height == 40.0); + } + + #[test] + fn test_inner_box() { + let b = Box2D::from_points(&[point2(50.0, 25.0), point2(100.0, 160.0)]); + let b = b.inner_box(SideOffsets2D::new(10.0, 20.0, 5.0, 10.0)); + assert_eq!(b.max.x, 80.0); + assert_eq!(b.max.y, 155.0); + assert_eq!(b.min.x, 60.0); + assert_eq!(b.min.y, 35.0); + } + + #[test] + fn test_outer_box() { + let b = Box2D::from_points(&[point2(50.0, 25.0), point2(100.0, 160.0)]); + let b = b.outer_box(SideOffsets2D::new(10.0, 20.0, 5.0, 10.0)); + assert_eq!(b.max.x, 120.0); + assert_eq!(b.max.y, 165.0); + assert_eq!(b.min.x, 40.0); + assert_eq!(b.min.y, 15.0); + } + + #[test] + fn test_translate() { + let size = size2(15.0, 15.0); + let mut center = (size / 2.0).to_vector().to_point(); + let b = Box2D::from_size(size); + assert_eq!(b.center(), center); + let translation = vec2(10.0, 2.5); + let b = b.translate(&translation); + center += translation; + assert_eq!(b.center(), center); + assert_eq!(b.max.x, 25.0); + assert_eq!(b.max.y, 17.5); + assert_eq!(b.min.x, 10.0); + assert_eq!(b.min.y, 2.5); + } + + #[test] + fn test_union() { + let b1 = Box2D::from_points(&[point2(-20.0, -20.0), point2(0.0, 20.0)]); + let b2 = Box2D::from_points(&[point2(0.0, 20.0), point2(20.0, -20.0)]); + let b = b1.union(&b2); + assert_eq!(b.max.x, 20.0); + assert_eq!(b.max.y, 20.0); + assert_eq!(b.min.x, -20.0); + assert_eq!(b.min.y, -20.0); + } + + #[test] + fn test_intersects() { + let b1 = Box2D::from_points(&[point2(-15.0, -20.0), point2(10.0, 20.0)]); + let b2 = Box2D::from_points(&[point2(-10.0, 20.0), point2(15.0, -20.0)]); + assert!(b1.intersects(&b2)); + } + + #[test] + fn test_intersection() { + let b1 = Box2D::from_points(&[point2(-15.0, -20.0), point2(10.0, 20.0)]); + let b2 = Box2D::from_points(&[point2(-10.0, 20.0), point2(15.0, -20.0)]); + let b = b1.intersection(&b2); + assert_eq!(b.max.x, 10.0); + assert_eq!(b.max.y, 20.0); + assert_eq!(b.min.x, -10.0); + assert_eq!(b.min.y, -20.0); + } + + #[test] + fn test_try_intersection() { + let b1 = Box2D::from_points(&[point2(-15.0, -20.0), point2(10.0, 20.0)]); + let b2 = Box2D::from_points(&[point2(-10.0, 20.0), point2(15.0, -20.0)]); + assert!(b1.try_intersection(&b2).is_some()); + + let b1 = Box2D::from_points(&[point2(-15.0, -20.0), point2(-10.0, 20.0)]); + let b2 = Box2D::from_points(&[point2(10.0, 20.0), point2(15.0, -20.0)]); + assert!(b1.try_intersection(&b2).is_none()); + } + + #[test] + fn test_scale() { + let b = Box2D::from_points(&[point2(-10.0, -10.0), point2(10.0, 10.0)]); + let b = b.scale(0.5, 0.5); + assert_eq!(b.max.x, 5.0); + assert_eq!(b.max.y, 5.0); + assert_eq!(b.min.x, -5.0); + assert_eq!(b.min.y, -5.0); + } + + #[test] + fn test_lerp() { + let b1 = Box2D::from_points(&[point2(-20.0, -20.0), point2(-10.0, -10.0)]); + let b2 = Box2D::from_points(&[point2(10.0, 10.0), point2(20.0, 20.0)]); + let b = b1.lerp(b2, 0.5); + assert_eq!(b.center(), Point2D::zero()); + assert_eq!(b.size().width, 10.0); + assert_eq!(b.size().height, 10.0); + } + + #[test] + fn test_contains() { + let b = Box2D::from_points(&[point2(-20.0, -20.0), point2(20.0, 20.0)]); + assert!(b.contains(&point2(-15.3, 10.5))); + } + + #[test] + fn test_contains_box() { + let b1 = Box2D::from_points(&[point2(-20.0, -20.0), point2(20.0, 20.0)]); + let b2 = Box2D::from_points(&[point2(-14.3, -16.5), point2(6.7, 17.6)]); + assert!(b1.contains_box(&b2)); + } + + #[test] + fn test_inflate() { + let b = Box2D::from_points(&[point2(-20.0, -20.0), point2(20.0, 20.0)]); + let b = b.inflate(10.0, 5.0); + assert_eq!(b.size().width, 60.0); + assert_eq!(b.size().height, 50.0); + assert_eq!(b.center(), Point2D::zero()); + } + + #[test] + fn test_is_empty() { + for i in 0..2 { + let mut coords_neg = [-20.0, -20.0]; + let mut coords_pos = [20.0, 20.0]; + coords_neg[i] = 0.0; + coords_pos[i] = 0.0; + let b = Box2D::from_points(&[Point2D::from(coords_neg), Point2D::from(coords_pos)]); + assert!(b.is_empty()); + } + } +} diff --git a/third_party/rust/euclid/src/box3d.rs b/third_party/rust/euclid/src/box3d.rs new file mode 100644 index 000000000000..5e71c3fb2d04 --- /dev/null +++ b/third_party/rust/euclid/src/box3d.rs @@ -0,0 +1,842 @@ +// Copyright 2013 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use super::UnknownUnit; +use length::Length; +use scale::TypedScale; +use num::*; +use point::TypedPoint3D; +use vector::TypedVector3D; +use size::TypedSize3D; +use approxord::{min, max}; + +use num_traits::NumCast; +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; + +use core::borrow::Borrow; +use core::cmp::PartialOrd; +use core::fmt; +use core::hash::{Hash, Hasher}; +use core::ops::{Add, Div, Mul, Sub}; + + +/// An axis aligned 3D box represented by its minimum and maximum coordinates. +#[repr(C)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "serde", serde(bound(serialize = "T: Serialize", deserialize = "T: Deserialize<'de>")))] +pub struct TypedBox3D { + pub min: TypedPoint3D, + pub max: TypedPoint3D, +} + +/// The default box 3d type with no unit. +pub type Box3D = TypedBox3D; + +impl Hash for TypedBox3D { + fn hash(&self, h: &mut H) { + self.min.hash(h); + self.max.hash(h); + } +} + +impl Copy for TypedBox3D {} + +impl Clone for TypedBox3D { + fn clone(&self) -> Self { + *self + } +} + +impl PartialEq> for TypedBox3D { + fn eq(&self, other: &Self) -> bool { + self.min.eq(&other.min) && self.max.eq(&other.max) + } +} + +impl Eq for TypedBox3D {} + +impl fmt::Debug for TypedBox3D { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "TypedBox3D({:?}, {:?})", self.min, self.max) + } +} + +impl fmt::Display for TypedBox3D { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "Box3D({}, {})", self.min, self.max) + } +} + +impl TypedBox3D { + /// Constructor. + pub fn new(min: TypedPoint3D, max: TypedPoint3D) -> Self { + TypedBox3D { + min, + max, + } + } +} + +impl TypedBox3D +where + T: Copy + Zero + PartialOrd, +{ + /// Creates a Box3D of the given size, at offset zero. + #[inline] + pub fn from_size(size: TypedSize3D) -> Self { + let zero = TypedPoint3D::zero(); + let point = size.to_vector().to_point(); + TypedBox3D::from_points(&[zero, point]) + } +} + +impl TypedBox3D +where + T: Copy + PartialOrd, +{ + /// Returns true if the box has a negative volume. + /// + /// The common interpretation for a negative box is to consider it empty. It can be obtained + /// by calculating the intersection of two boxes that do not intersect. + #[inline] + pub fn is_negative(&self) -> bool { + self.max.x < self.min.x || self.max.y < self.min.y || self.max.z < self.min.z + } + + /// Returns true if the size is zero or negative. + #[inline] + pub fn is_empty_or_negative(&self) -> bool { + self.max.x <= self.min.x || self.max.y <= self.min.y || self.max.z <= self.min.z + } + + + #[inline] + pub fn intersects(&self, other: &Self) -> bool { + self.min.x < other.max.x + && self.max.x > other.min.x + && self.min.y < other.max.y + && self.max.y > other.min.y + && self.min.z < other.max.z + && self.max.z > other.min.z + } + + #[inline] + pub fn try_intersection(&self, other: &Self) -> Option { + if !self.intersects(other) { + return None; + } + + Some(self.intersection(other)) + } + + pub fn intersection(&self, other: &Self) -> Self { + let intersection_min = TypedPoint3D::new( + max(self.min.x, other.min.x), + max(self.min.y, other.min.y), + max(self.min.z, other.min.z), + ); + + let intersection_max = TypedPoint3D::new( + min(self.max.x, other.max.x), + min(self.max.y, other.max.y), + min(self.max.z, other.max.z), + ); + + TypedBox3D::new( + intersection_min, + intersection_max, + ) + } +} + +impl TypedBox3D +where + T: Copy + Add, +{ + /// Returns the same box3d, translated by a vector. + #[inline] + #[cfg_attr(feature = "unstable", must_use)] + pub fn translate(&self, by: &TypedVector3D) -> Self { + Self::new(self.min + *by, self.max + *by) + } +} + +impl TypedBox3D +where + T: Copy + PartialOrd + Zero, +{ + /// Returns true if this box3d contains the point. Points are considered + /// in the box3d if they are on the front, left or top faces, but outside if they + /// are on the back, right or bottom faces. + #[inline] + pub fn contains(&self, other: &TypedPoint3D) -> bool { + self.min.x <= other.x && other.x < self.max.x + && self.min.y <= other.y && other.y < self.max.y + && self.min.z <= other.z && other.z < self.max.z + } +} + +impl TypedBox3D +where + T: Copy + PartialOrd + Zero + Sub, +{ + /// Returns true if this box3d contains the interior of the other box3d. Always + /// returns true if other is empty, and always returns false if other is + /// nonempty but this box3d is empty. + #[inline] + pub fn contains_box(&self, other: &Self) -> bool { + other.is_empty_or_negative() + || (self.min.x <= other.min.x && other.max.x <= self.max.x + && self.min.y <= other.min.y && other.max.y <= self.max.y + && self.min.z <= other.min.z && other.max.z <= self.max.z) + } +} + +impl TypedBox3D +where + T: Copy + Sub, +{ + #[inline] + pub fn size(&self)-> TypedSize3D { + TypedSize3D::new( + self.max.x - self.min.x, + self.max.y - self.min.y, + self.max.z - self.min.z, + ) + } +} + +impl TypedBox3D +where + T: Copy + PartialEq + Add + Sub, +{ + /// Inflates the box by the specified sizes on each side respectively. + #[inline] + #[cfg_attr(feature = "unstable", must_use)] + pub fn inflate(&self, width: T, height: T, depth: T) -> Self { + TypedBox3D::new( + TypedPoint3D::new(self.min.x - width, self.min.y - height, self.min.z - depth), + TypedPoint3D::new(self.max.x + width, self.max.y + height, self.max.z + depth), + ) + } + + #[inline] + #[cfg_attr(feature = "unstable", must_use)] + pub fn inflate_typed(&self, width: Length, height: Length, depth: Length) -> Self { + self.inflate(width.get(), height.get(), depth.get()) + } +} + +impl TypedBox3D +where + T: Copy + Zero + PartialOrd, +{ + /// Returns the smallest box containing all of the provided points. + pub fn from_points(points: I) -> Self + where + I: IntoIterator, + I::Item: Borrow>, + { + let mut points = points.into_iter(); + + // Need at least 2 different points for a valid box3d (ie: volume > 0). + let (mut min_x, mut min_y, mut min_z) = match points.next() { + Some(first) => (first.borrow().x, first.borrow().y, first.borrow().z), + None => return TypedBox3D::zero(), + }; + let (mut max_x, mut max_y, mut max_z) = (min_x, min_y, min_z); + + { + let mut assign_min_max = |point: I::Item| { + let p = point.borrow(); + if p.x < min_x { + min_x = p.x + } + if p.x > max_x { + max_x = p.x + } + if p.y < min_y { + min_y = p.y + } + if p.y > max_y { + max_y = p.y + } + if p.z < min_z { + min_z = p.z + } + if p.z > max_z { + max_z = p.z + } + }; + + match points.next() { + Some(second) => assign_min_max(second), + None => return TypedBox3D::zero(), + } + + for point in points { + assign_min_max(point); + } + } + + Self::new(TypedPoint3D::new(min_x, min_y, min_z), TypedPoint3D::new(max_x, max_y, max_z)) + } +} + +impl TypedBox3D +where + T: Copy + One + Add + Sub + Mul, +{ + /// Linearly interpolate between this box3d and another box3d. + /// + /// `t` is expected to be between zero and one. + #[inline] + pub fn lerp(&self, other: Self, t: T) -> Self { + Self::new( + self.min.lerp(other.min, t), + self.max.lerp(other.max, t), + ) + } +} + +impl TypedBox3D +where + T: Copy + One + Add + Div, +{ + pub fn center(&self) -> TypedPoint3D { + let two = T::one() + T::one(); + (self.min + self.max.to_vector()) / two + } +} + +impl TypedBox3D +where + T: Copy + Clone + PartialOrd + Add + Sub + Zero, +{ + #[inline] + pub fn union(&self, other: &Self) -> Self { + TypedBox3D::new( + TypedPoint3D::new( + min(self.min.x, other.min.x), + min(self.min.y, other.min.y), + min(self.min.z, other.min.z), + ), + TypedPoint3D::new( + max(self.max.x, other.max.x), + max(self.max.y, other.max.y), + max(self.max.z, other.max.z), + ), + ) + } +} + +impl TypedBox3D +where + T: Copy, +{ + #[inline] + pub fn scale(&self, x: S, y: S, z: S) -> Self + where + T: Mul + { + TypedBox3D::new( + TypedPoint3D::new(self.min.x * x, self.min.y * y, self.min.z * z), + TypedPoint3D::new(self.max.x * x, self.max.y * y, self.max.z * z), + ) + } +} + +impl TypedBox3D +where + T: Copy + Mul + Sub, +{ + #[inline] + pub fn volume(&self) -> T { + let size = self.size(); + size.width * size.height * size.depth + } + + #[inline] + pub fn xy_area(&self) -> T { + let size = self.size(); + size.width * size.height + } + + #[inline] + pub fn yz_area(&self) -> T { + let size = self.size(); + size.depth * size.height + } + + #[inline] + pub fn xz_area(&self) -> T { + let size = self.size(); + size.depth * size.width + } +} + +impl TypedBox3D +where + T: Copy + Zero, +{ + /// Constructor, setting all sides to zero. + pub fn zero() -> Self { + TypedBox3D::new(TypedPoint3D::zero(), TypedPoint3D::zero()) + } +} + +impl TypedBox3D +where + T: PartialEq, +{ + /// Returns true if the volume is zero. + #[inline] + pub fn is_empty(&self) -> bool { + self.min.x == self.max.x || self.min.y == self.max.y || self.min.z == self.max.z + } +} + +impl Mul for TypedBox3D +where + T: Copy + Mul, +{ + type Output = Self; + #[inline] + fn mul(self, scale: T) -> Self { + TypedBox3D::new(self.min * scale, self.max * scale) + } +} + +impl Div for TypedBox3D +where + T: Copy + Div, +{ + type Output = Self; + #[inline] + fn div(self, scale: T) -> Self { + TypedBox3D::new(self.min / scale, self.max / scale) + } +} + +impl Mul> for TypedBox3D +where + T: Copy + Mul, +{ + type Output = TypedBox3D; + #[inline] + fn mul(self, scale: TypedScale) -> TypedBox3D { + TypedBox3D::new(self.min * scale, self.max * scale) + } +} + +impl Div> for TypedBox3D +where + T: Copy + Div, +{ + type Output = TypedBox3D; + #[inline] + fn div(self, scale: TypedScale) -> TypedBox3D { + TypedBox3D::new(self.min / scale, self.max / scale) + } +} + +impl TypedBox3D +where + T: Copy, +{ + /// Drop the units, preserving only the numeric value. + pub fn to_untyped(&self) -> Box3D { + TypedBox3D::new(self.min.to_untyped(), self.max.to_untyped()) + } + + /// Tag a unitless value with units. + pub fn from_untyped(c: &Box3D) -> TypedBox3D { + TypedBox3D::new( + TypedPoint3D::from_untyped(&c.min), + TypedPoint3D::from_untyped(&c.max), + ) + } +} + +impl TypedBox3D +where + T0: NumCast + Copy, +{ + /// Cast from one numeric representation to another, preserving the units. + /// + /// When casting from floating point to integer coordinates, the decimals are truncated + /// as one would expect from a simple cast, but this behavior does not always make sense + /// geometrically. Consider using round(), round_in or round_out() before casting. + pub fn cast(&self) -> TypedBox3D { + TypedBox3D::new( + self.min.cast(), + self.max.cast(), + ) + } + + /// Fallible cast from one numeric representation to another, preserving the units. + /// + /// When casting from floating point to integer coordinates, the decimals are truncated + /// as one would expect from a simple cast, but this behavior does not always make sense + /// geometrically. Consider using round(), round_in or round_out() before casting. + pub fn try_cast(&self) -> Option> { + match (self.min.try_cast(), self.max.try_cast()) { + (Some(a), Some(b)) => Some(TypedBox3D::new(a, b)), + _ => None, + } + } +} + +impl TypedBox3D +where + T: Round, +{ + /// Return a box3d with edges rounded to integer coordinates, such that + /// the returned box3d has the same set of pixel centers as the original + /// one. + /// Values equal to 0.5 round up. + /// Suitable for most places where integral device coordinates + /// are needed, but note that any translation should be applied first to + /// avoid pixel rounding errors. + /// Note that this is *not* rounding to nearest integer if the values are negative. + /// They are always rounding as floor(n + 0.5). + #[cfg_attr(feature = "unstable", must_use)] + pub fn round(&self) -> Self { + TypedBox3D::new(self.min.round(), self.max.round()) + } +} + +impl TypedBox3D +where + T: Floor + Ceil, +{ + /// Return a box3d with faces/edges rounded to integer coordinates, such that + /// the original box3d contains the resulting box3d. + #[cfg_attr(feature = "unstable", must_use)] + pub fn round_in(&self) -> Self { + TypedBox3D { + min: self.min.ceil(), + max: self.max.floor(), + } + } + + /// Return a box3d with faces/edges rounded to integer coordinates, such that + /// the original box3d is contained in the resulting box3d. + #[cfg_attr(feature = "unstable", must_use)] + pub fn round_out(&self) -> Self { + TypedBox3D { + min: self.min.floor(), + max: self.max.ceil(), + } + } +} + +// Convenience functions for common casts +impl TypedBox3D { + /// Cast into an `f32` box3d. + pub fn to_f32(&self) -> TypedBox3D { + self.cast() + } + + /// Cast into an `f64` box3d. + pub fn to_f64(&self) -> TypedBox3D { + self.cast() + } + + /// Cast into an `usize` box3d, truncating decimals if any. + /// + /// When casting from floating point cuboids, it is worth considering whether + /// to `round()`, `round_in()` or `round_out()` before the cast in order to + /// obtain the desired conversion behavior. + pub fn to_usize(&self) -> TypedBox3D { + self.cast() + } + + /// Cast into an `u32` box3d, truncating decimals if any. + /// + /// When casting from floating point cuboids, it is worth considering whether + /// to `round()`, `round_in()` or `round_out()` before the cast in order to + /// obtain the desired conversion behavior. + pub fn to_u32(&self) -> TypedBox3D { + self.cast() + } + + /// Cast into an `i32` box3d, truncating decimals if any. + /// + /// When casting from floating point cuboids, it is worth considering whether + /// to `round()`, `round_in()` or `round_out()` before the cast in order to + /// obtain the desired conversion behavior. + pub fn to_i32(&self) -> TypedBox3D { + self.cast() + } + + /// Cast into an `i64` box3d, truncating decimals if any. + /// + /// When casting from floating point cuboids, it is worth considering whether + /// to `round()`, `round_in()` or `round_out()` before the cast in order to + /// obtain the desired conversion behavior. + pub fn to_i64(&self) -> TypedBox3D { + self.cast() + } +} + +impl From> for TypedBox3D +where + T: Copy + Zero + PartialOrd, +{ + fn from(b: TypedSize3D) -> Self { + Self::from_size(b) + } +} + +/// Shorthand for `TypedBox3D::new(TypedPoint3D::new(x1, y1, z1), TypedPoint3D::new(x2, y2, z2))`. +pub fn box3d(min_x: T, min_y: T, min_z: T, max_x: T, max_y: T, max_z: T) -> TypedBox3D { + TypedBox3D::new(TypedPoint3D::new(min_x, min_y, min_z), TypedPoint3D::new(max_x, max_y, max_z)) +} + +#[cfg(test)] +mod tests { + use vector::vec3; + use size::size3; + use point::{point3, Point3D}; + use super::*; + + #[test] + fn test_new() { + let b = Box3D::new(point3(-1.0, -1.0, -1.0), point3(1.0, 1.0, 1.0)); + assert!(b.min.x == -1.0); + assert!(b.min.y == -1.0); + assert!(b.min.z == -1.0); + assert!(b.max.x == 1.0); + assert!(b.max.y == 1.0); + assert!(b.max.z == 1.0); + } + + #[test] + fn test_size() { + let b = Box3D::new(point3(-10.0, -10.0, -10.0), point3(10.0, 10.0, 10.0)); + assert!(b.size().width == 20.0); + assert!(b.size().height == 20.0); + assert!(b.size().depth == 20.0); + } + + #[test] + fn test_center() { + let b = Box3D::new(point3(-10.0, -10.0, -10.0), point3(10.0, 10.0, 10.0)); + assert!(b.center() == Point3D::zero()); + } + + #[test] + fn test_volume() { + let b = Box3D::new(point3(-10.0, -10.0, -10.0), point3(10.0, 10.0, 10.0)); + assert!(b.volume() == 8000.0); + } + + #[test] + fn test_area() { + let b = Box3D::new(point3(-10.0, -10.0, -10.0), point3(10.0, 10.0, 10.0)); + assert!(b.xy_area() == 400.0); + assert!(b.yz_area() == 400.0); + assert!(b.xz_area() == 400.0); + } + + #[test] + fn test_from_points() { + let b = Box3D::from_points(&[point3(50.0, 160.0, 12.5), point3(100.0, 25.0, 200.0)]); + assert!(b.min == point3(50.0, 25.0, 12.5)); + assert!(b.max == point3(100.0, 160.0, 200.0)); + } + + #[test] + fn test_min_max() { + let b = Box3D::from_points(&[point3(50.0, 25.0, 12.5), point3(100.0, 160.0, 200.0)]); + assert!(b.min.x == 50.0); + assert!(b.min.y == 25.0); + assert!(b.min.z == 12.5); + assert!(b.max.x == 100.0); + assert!(b.max.y == 160.0); + assert!(b.max.z == 200.0); + } + + #[test] + fn test_round_in() { + let b = Box3D::from_points(&[point3(-25.5, -40.4, -70.9), point3(60.3, 36.5, 89.8)]).round_in(); + assert!(b.min.x == -25.0); + assert!(b.min.y == -40.0); + assert!(b.min.z == -70.0); + assert!(b.max.x == 60.0); + assert!(b.max.y == 36.0); + assert!(b.max.z == 89.0); + } + + #[test] + fn test_round_out() { + let b = Box3D::from_points(&[point3(-25.5, -40.4, -70.9), point3(60.3, 36.5, 89.8)]).round_out(); + assert!(b.min.x == -26.0); + assert!(b.min.y == -41.0); + assert!(b.min.z == -71.0); + assert!(b.max.x == 61.0); + assert!(b.max.y == 37.0); + assert!(b.max.z == 90.0); + } + + #[test] + fn test_round() { + let b = Box3D::from_points(&[point3(-25.5, -40.4, -70.9), point3(60.3, 36.5, 89.8)]).round(); + assert!(b.min.x == -26.0); + assert!(b.min.y == -40.0); + assert!(b.min.z == -71.0); + assert!(b.max.x == 60.0); + assert!(b.max.y == 37.0); + assert!(b.max.z == 90.0); + } + + #[test] + fn test_from_size() { + let b = Box3D::from_size(size3(30.0, 40.0, 50.0)); + assert!(b.min == Point3D::zero()); + assert!(b.size().width == 30.0); + assert!(b.size().height == 40.0); + assert!(b.size().depth == 50.0); + } + + #[test] + fn test_translate() { + let size = size3(15.0, 15.0, 200.0); + let mut center = (size / 2.0).to_vector().to_point(); + let b = Box3D::from_size(size); + assert!(b.center() == center); + let translation = vec3(10.0, 2.5, 9.5); + let b = b.translate(&translation); + center += translation; + assert!(b.center() == center); + assert!(b.max.x == 25.0); + assert!(b.max.y == 17.5); + assert!(b.max.z == 209.5); + assert!(b.min.x == 10.0); + assert!(b.min.y == 2.5); + assert!(b.min.z == 9.5); + } + + #[test] + fn test_union() { + let b1 = Box3D::from_points(&[point3(-20.0, -20.0, -20.0), point3(0.0, 20.0, 20.0)]); + let b2 = Box3D::from_points(&[point3(0.0, 20.0, 20.0), point3(20.0, -20.0, -20.0)]); + let b = b1.union(&b2); + assert!(b.max.x == 20.0); + assert!(b.max.y == 20.0); + assert!(b.max.z == 20.0); + assert!(b.min.x == -20.0); + assert!(b.min.y == -20.0); + assert!(b.min.z == -20.0); + assert!(b.volume() == (40.0 * 40.0 * 40.0)); + } + + #[test] + fn test_intersects() { + let b1 = Box3D::from_points(&[point3(-15.0, -20.0, -20.0), point3(10.0, 20.0, 20.0)]); + let b2 = Box3D::from_points(&[point3(-10.0, 20.0, 20.0), point3(15.0, -20.0, -20.0)]); + assert!(b1.intersects(&b2)); + } + + #[test] + fn test_intersection() { + let b1 = Box3D::from_points(&[point3(-15.0, -20.0, -20.0), point3(10.0, 20.0, 20.0)]); + let b2 = Box3D::from_points(&[point3(-10.0, 20.0, 20.0), point3(15.0, -20.0, -20.0)]); + let b = b1.intersection(&b2); + assert!(b.max.x == 10.0); + assert!(b.max.y == 20.0); + assert!(b.max.z == 20.0); + assert!(b.min.x == -10.0); + assert!(b.min.y == -20.0); + assert!(b.min.z == -20.0); + assert!(b.volume() == (20.0 * 40.0 * 40.0)); + } + + #[test] + fn test_try_intersection() { + let b1 = Box3D::from_points(&[point3(-15.0, -20.0, -20.0), point3(10.0, 20.0, 20.0)]); + let b2 = Box3D::from_points(&[point3(-10.0, 20.0, 20.0), point3(15.0, -20.0, -20.0)]); + assert!(b1.try_intersection(&b2).is_some()); + + let b1 = Box3D::from_points(&[point3(-15.0, -20.0, -20.0), point3(-10.0, 20.0, 20.0)]); + let b2 = Box3D::from_points(&[point3(10.0, 20.0, 20.0), point3(15.0, -20.0, -20.0)]); + assert!(b1.try_intersection(&b2).is_none()); + } + + #[test] + fn test_scale() { + let b = Box3D::from_points(&[point3(-10.0, -10.0, -10.0), point3(10.0, 10.0, 10.0)]); + let b = b.scale(0.5, 0.5, 0.5); + assert!(b.max.x == 5.0); + assert!(b.max.y == 5.0); + assert!(b.max.z == 5.0); + assert!(b.min.x == -5.0); + assert!(b.min.y == -5.0); + assert!(b.min.z == -5.0); + } + + #[test] + fn test_zero() { + let b = Box3D::::zero(); + assert!(b.max.x == 0.0); + assert!(b.max.y == 0.0); + assert!(b.max.z == 0.0); + assert!(b.min.x == 0.0); + assert!(b.min.y == 0.0); + assert!(b.min.z == 0.0); + } + + #[test] + fn test_lerp() { + let b1 = Box3D::from_points(&[point3(-20.0, -20.0, -20.0), point3(-10.0, -10.0, -10.0)]); + let b2 = Box3D::from_points(&[point3(10.0, 10.0, 10.0), point3(20.0, 20.0, 20.0)]); + let b = b1.lerp(b2, 0.5); + assert!(b.center() == Point3D::zero()); + assert!(b.size().width == 10.0); + assert!(b.size().height == 10.0); + assert!(b.size().depth == 10.0); + } + + #[test] + fn test_contains() { + let b = Box3D::from_points(&[point3(-20.0, -20.0, -20.0), point3(20.0, 20.0, 20.0)]); + assert!(b.contains(&point3(-15.3, 10.5, 18.4))); + } + + #[test] + fn test_contains_box() { + let b1 = Box3D::from_points(&[point3(-20.0, -20.0, -20.0), point3(20.0, 20.0, 20.0)]); + let b2 = Box3D::from_points(&[point3(-14.3, -16.5, -19.3), point3(6.7, 17.6, 2.5)]); + assert!(b1.contains_box(&b2)); + } + + #[test] + fn test_inflate() { + let b = Box3D::from_points(&[point3(-20.0, -20.0, -20.0), point3(20.0, 20.0, 20.0)]); + let b = b.inflate(10.0, 5.0, 2.0); + assert!(b.size().width == 60.0); + assert!(b.size().height == 50.0); + assert!(b.size().depth == 44.0); + assert!(b.center() == Point3D::zero()); + } + + #[test] + fn test_is_empty() { + for i in 0..3 { + let mut coords_neg = [-20.0, -20.0, -20.0]; + let mut coords_pos = [20.0, 20.0, 20.0]; + coords_neg[i] = 0.0; + coords_pos[i] = 0.0; + let b = Box3D::from_points(&[Point3D::from(coords_neg), Point3D::from(coords_pos)]); + assert!(b.is_empty()); + } + } +} diff --git a/third_party/rust/euclid/src/lib.rs b/third_party/rust/euclid/src/lib.rs index 79873fd40126..f604ab8d39c4 100644 --- a/third_party/rust/euclid/src/lib.rs +++ b/third_party/rust/euclid/src/lib.rs @@ -70,6 +70,7 @@ extern crate rand; #[cfg(test)] use std as core; +pub use box2d::{TypedBox2D, Box2D}; pub use length::Length; pub use scale::TypedScale; pub use transform2d::{Transform2D, TypedTransform2D}; @@ -80,6 +81,8 @@ pub use vector::{BoolVector2D, BoolVector3D, bvec2, bvec3}; pub use homogen::HomogeneousVector; pub use rect::{rect, Rect, TypedRect}; +pub use rigid::{RigidTransform3D, TypedRigidTransform3D}; +pub use box3d::{box3d, Box3D, TypedBox3D}; pub use translation::{TypedTranslation2D, TypedTranslation3D}; pub use rotation::{Angle, Rotation2D, Rotation3D, TypedRotation2D, TypedRotation3D}; pub use side_offsets::{SideOffsets2D, TypedSideOffsets2D}; @@ -90,11 +93,14 @@ pub use trig::Trig; mod macros; pub mod approxeq; +pub mod approxord; +mod box2d; mod homogen; pub mod num; mod length; mod point; mod rect; +mod rigid; mod rotation; mod scale; mod side_offsets; @@ -104,9 +110,10 @@ mod transform3d; mod translation; mod trig; mod vector; +mod box3d; /// The default unit. -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct UnknownUnit; /// Temporary alias to facilitate the transition to the new naming scheme diff --git a/third_party/rust/euclid/src/point.rs b/third_party/rust/euclid/src/point.rs index b9df69d0880a..dc8debb99072 100644 --- a/third_party/rust/euclid/src/point.rs +++ b/third_party/rust/euclid/src/point.rs @@ -11,7 +11,7 @@ use super::UnknownUnit; use approxeq::ApproxEq; use length::Length; use scale::TypedScale; -use size::TypedSize2D; +use size::{TypedSize2D, TypedSize3D}; #[cfg(feature = "mint")] use mint; use num::*; @@ -69,6 +69,12 @@ impl fmt::Display for TypedPoint2D { } } +impl Default for TypedPoint2D { + fn default() -> Self { + TypedPoint2D::new(Default::default(), Default::default()) + } +} + impl TypedPoint2D { /// Constructor taking scalar values directly. #[inline] @@ -136,6 +142,11 @@ impl TypedPoint2D { pub fn to_array(&self) -> [T; 2] { [self.x, self.y] } + + #[inline] + pub fn to_tuple(&self) -> (T, T) { + (self.x, self.y) + } } impl, U> TypedPoint2D { @@ -411,6 +422,18 @@ impl From<[T; 2]> for TypedPoint2D { } } +impl Into<(T, T)> for TypedPoint2D { + fn into(self) -> (T, T) { + self.to_tuple() + } +} + +impl From<(T, T)> for TypedPoint2D { + fn from(tuple: (T, T)) -> Self { + point2(tuple.0, tuple.1) + } +} + /// A 3d Point tagged with a unit. #[derive(EuclidMatrix)] #[repr(C)] @@ -435,6 +458,11 @@ impl TypedPoint3D { pub fn origin() -> Self { point3(Zero::zero(), Zero::zero(), Zero::zero()) } + + #[inline] + pub fn zero() -> Self { + Self::origin() + } } impl TypedPoint3D { @@ -442,6 +470,11 @@ impl TypedPoint3D { pub fn to_array_4d(&self) -> [T; 4] { [self.x, self.y, self.z, One::one()] } + + #[inline] + pub fn to_tuple_4d(&self) -> (T, T, T, T) { + (self.x, self.y, self.z, One::one()) + } } impl TypedPoint3D @@ -474,6 +507,12 @@ impl fmt::Display for TypedPoint3D { } } +impl Default for TypedPoint3D { + fn default() -> Self { + TypedPoint3D::new(Default::default(), Default::default(), Default::default()) + } +} + impl TypedPoint3D { /// Constructor taking scalar values directly. #[inline] @@ -541,6 +580,11 @@ impl TypedPoint3D { [self.x, self.y, self.z] } + #[inline] + pub fn to_tuple(&self) -> (T, T, T) { + (self.x, self.y, self.z) + } + /// Drop the units, preserving only the numeric value. #[inline] pub fn to_untyped(&self) -> Point3D { @@ -560,6 +604,13 @@ impl TypedPoint3D { } } +impl, U> TypedPoint3D { + #[inline] + pub fn add_size(&self, other: &TypedSize3D) -> Self { + point3(self.x + other.width, self.y + other.height, self.z + other.depth) + } +} + impl, U> AddAssign> for TypedPoint3D { #[inline] fn add_assign(&mut self, other: TypedVector3D) { @@ -606,6 +657,14 @@ impl, U> Mul for TypedPoint3D { } } +impl, U1, U2> Mul> for TypedPoint3D { + type Output = TypedPoint3D; + #[inline] + fn mul(self, scale: TypedScale) -> TypedPoint3D { + point3(self.x * scale.get(), self.y * scale.get(), self.z * scale.get()) + } +} + impl, U> Div for TypedPoint3D { type Output = Self; #[inline] @@ -614,6 +673,14 @@ impl, U> Div for TypedPoint3D { } } +impl, U1, U2> Div> for TypedPoint3D { + type Output = TypedPoint3D; + #[inline] + fn div(self, scale: TypedScale) -> TypedPoint3D { + point3(self.x / scale.get(), self.y / scale.get(), self.z / scale.get()) + } +} + impl TypedPoint3D { #[inline] pub fn min(self, other: Self) -> Self { @@ -789,6 +856,18 @@ impl From<[T; 3]> for TypedPoint3D { } } +impl Into<(T, T, T)> for TypedPoint3D { + fn into(self) -> (T, T, T) { + self.to_tuple() + } +} + +impl From<(T, T, T)> for TypedPoint3D { + fn from(tuple: (T, T, T)) -> Self { + point3(tuple.0, tuple.1, tuple.2) + } +} + pub fn point2(x: T, y: T) -> TypedPoint2D { TypedPoint2D::new(x, y) } diff --git a/third_party/rust/euclid/src/rect.rs b/third_party/rust/euclid/src/rect.rs index a382e37b6a84..9db9c29affc8 100644 --- a/third_party/rust/euclid/src/rect.rs +++ b/third_party/rust/euclid/src/rect.rs @@ -11,10 +11,12 @@ use super::UnknownUnit; use length::Length; use scale::TypedScale; use num::*; +use box2d::TypedBox2D; use point::TypedPoint2D; use vector::TypedVector2D; use side_offsets::TypedSideOffsets2D; use size::TypedSize2D; +use approxord::{min, max}; use num_traits::NumCast; #[cfg(feature = "serde")] @@ -93,6 +95,12 @@ impl fmt::Display for TypedRect { } } +impl Default for TypedRect { + fn default() -> Self { + TypedRect::new(Default::default(), Default::default()) + } +} + impl TypedRect { /// Constructor. pub fn new(origin: TypedPoint2D, size: TypedSize2D) -> Self { @@ -256,6 +264,14 @@ where TypedPoint2D::new(self.max_x(), self.max_y()) } + #[inline] + pub fn to_box2d(&self) -> TypedBox2D { + TypedBox2D { + min: self.origin, + max: self.bottom_right(), + } + } + #[inline] #[cfg_attr(feature = "unstable", must_use)] pub fn translate_by_size(&self, size: &TypedSize2D) -> Self { @@ -428,22 +444,6 @@ impl TypedRect { } } -pub fn min(x: T, y: T) -> T { - if x <= y { - x - } else { - y - } -} - -pub fn max(x: T, y: T) -> T { - if x >= y { - x - } else { - y - } -} - impl, U> Mul for TypedRect { type Output = Self; #[inline] @@ -623,15 +623,6 @@ mod tests { use size::Size2D; use super::*; - #[test] - fn test_min_max() { - assert!(min(0u32, 1u32) == 0u32); - assert!(min(-1.0f32, 0.0f32) == -1.0f32); - - assert!(max(0u32, 1u32) == 1u32); - assert!(max(-1.0f32, 0.0f32) == 0.0f32); - } - #[test] fn test_translate() { let p = Rect::new(Point2D::new(0u32, 0u32), Size2D::new(50u32, 40u32)); diff --git a/third_party/rust/euclid/src/rigid.rs b/third_party/rust/euclid/src/rigid.rs new file mode 100644 index 000000000000..46ddd4e8a0bd --- /dev/null +++ b/third_party/rust/euclid/src/rigid.rs @@ -0,0 +1,261 @@ +use approxeq::ApproxEq; +use num_traits::Float; +use trig::Trig; +use {TypedRotation3D, TypedTransform3D, TypedVector3D, UnknownUnit}; + +/// A rigid transformation. All lengths are preserved under such a transformation. +/// +/// +/// Internally, this is a rotation and a translation, with the rotation +/// applied first (i.e. `Rotation * Translation`, in row-vector notation) +/// +/// This can be more efficient to use over full matrices, especially if you +/// have to deal with the decomposed quantities often. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[repr(C)] +pub struct TypedRigidTransform3D { + pub rotation: TypedRotation3D, + pub translation: TypedVector3D, +} + +pub type RigidTransform3D = TypedRigidTransform3D; + +// All matrix multiplication in this file is in row-vector notation, +// i.e. a vector `v` is transformed with `v * T`, and if you want to apply `T1` +// before `T2` you use `T1 * T2` + +impl, Src, Dst> TypedRigidTransform3D { + /// Construct a new rigid transformation, where the `rotation` applies first + #[inline] + pub fn new(rotation: TypedRotation3D, translation: TypedVector3D) -> Self { + Self { + rotation, + translation, + } + } + + /// Construct an identity transform + #[inline] + pub fn identity() -> Self { + Self { + rotation: TypedRotation3D::identity(), + translation: TypedVector3D::zero(), + } + } + + /// Construct a new rigid transformation, where the `translation` applies first + #[inline] + pub fn new_from_reversed( + translation: TypedVector3D, + rotation: TypedRotation3D, + ) -> Self { + // T * R + // = (R * R^-1) * T * R + // = R * (R^-1 * T * R) + // = R * T' + // + // T' = (R^-1 * T * R) is also a translation matrix + // It is equivalent to the translation matrix obtained by rotating the + // translation by R + + let translation = rotation.rotate_vector3d(&translation); + Self { + rotation, + translation, + } + } + + #[inline] + pub fn from_rotation(rotation: TypedRotation3D) -> Self { + Self { + rotation, + translation: TypedVector3D::zero(), + } + } + + #[inline] + pub fn from_translation(translation: TypedVector3D) -> Self { + Self { + translation, + rotation: TypedRotation3D::identity(), + } + } + + /// Decompose this into a translation and an rotation to be applied in the opposite order + /// + /// i.e., the translation is applied _first_ + #[inline] + pub fn decompose_reversed(&self) -> (TypedVector3D, TypedRotation3D) { + // self = R * T + // = R * T * (R^-1 * R) + // = (R * T * R^-1) * R) + // = T' * R + // + // T' = (R^ * T * R^-1) is T rotated by R^-1 + + let translation = self.rotation.inverse().rotate_vector3d(&self.translation); + (translation, self.rotation) + } + + /// Returns the multiplication of the two transforms such that + /// other's transformation applies after self's transformation. + /// + /// i.e., this produces `self * other` in row-vector notation + #[inline] + pub fn post_mul( + &self, + other: &TypedRigidTransform3D, + ) -> TypedRigidTransform3D { + // self = R1 * T1 + // other = R2 * T2 + // result = R1 * T1 * R2 * T2 + // = R1 * (R2 * R2^-1) * T1 * R2 * T2 + // = (R1 * R2) * (R2^-1 * T1 * R2) * T2 + // = R' * T' * T2 + // = R' * T'' + // + // (R2^-1 * T2 * R2^) = T' = T2 rotated by R2 + // R1 * R2 = R' + // T' * T2 = T'' = vector addition of translations T2 and T' + + let t_prime = other + .rotation + .rotate_vector3d(&self.translation); + let r_prime = self.rotation.post_rotate(&other.rotation); + let t_prime2 = t_prime + other.translation; + TypedRigidTransform3D { + rotation: r_prime, + translation: t_prime2, + } + } + + /// Returns the multiplication of the two transforms such that + /// self's transformation applies after other's transformation. + /// + /// i.e., this produces `other * self` in row-vector notation + #[inline] + pub fn pre_mul( + &self, + other: &TypedRigidTransform3D, + ) -> TypedRigidTransform3D { + other.post_mul(&self) + } + + /// Inverts the transformation + #[inline] + pub fn inverse(&self) -> TypedRigidTransform3D { + // result = (self)^-1 + // = (R * T)^-1 + // = T^-1 * R^-1 + // = (R^-1 * R) * T^-1 * R^-1 + // = R^-1 * (R * T^-1 * R^-1) + // = R' * T' + // + // T' = (R * T^-1 * R^-1) = (-T) rotated by R^-1 + // R' = R^-1 + // + // An easier way of writing this is to use new_from_reversed() with R^-1 and T^-1 + + TypedRigidTransform3D::new_from_reversed( + -self.translation, + self.rotation.inverse(), + ) + } + + pub fn to_transform(&self) -> TypedTransform3D + where + T: Trig, + { + self.translation + .to_transform() + .pre_mul(&self.rotation.to_transform()) + } +} + +impl, Src, Dst> From> + for TypedRigidTransform3D +{ + fn from(rot: TypedRotation3D) -> Self { + Self::from_rotation(rot) + } +} + +impl, Src, Dst> From> + for TypedRigidTransform3D +{ + fn from(t: TypedVector3D) -> Self { + Self::from_translation(t) + } +} + +#[cfg(test)] +mod test { + use super::RigidTransform3D; + use {Rotation3D, TypedTransform3D, Vector3D}; + + #[test] + fn test_rigid_construction() { + let translation = Vector3D::new(12.1, 17.8, -5.5); + let rotation = Rotation3D::unit_quaternion(0.5, -7.8, 2.2, 4.3); + + let rigid = RigidTransform3D::new(rotation, translation); + assert!(rigid + .to_transform() + .approx_eq(&translation.to_transform().pre_mul(&rotation.to_transform()))); + + let rigid = RigidTransform3D::new_from_reversed(translation, rotation); + assert!(rigid.to_transform().approx_eq( + &translation + .to_transform() + .post_mul(&rotation.to_transform()) + )); + } + + #[test] + fn test_rigid_decomposition() { + let translation = Vector3D::new(12.1, 17.8, -5.5); + let rotation = Rotation3D::unit_quaternion(0.5, -7.8, 2.2, 4.3); + + let rigid = RigidTransform3D::new(rotation, translation); + let (t2, r2) = rigid.decompose_reversed(); + assert!(rigid + .to_transform() + .approx_eq(&t2.to_transform().post_mul(&r2.to_transform()))); + } + + #[test] + fn test_rigid_inverse() { + let translation = Vector3D::new(12.1, 17.8, -5.5); + let rotation = Rotation3D::unit_quaternion(0.5, -7.8, 2.2, 4.3); + + let rigid = RigidTransform3D::new(rotation, translation); + let inverse = rigid.inverse(); + assert!(rigid + .post_mul(&inverse) + .to_transform() + .approx_eq(&TypedTransform3D::identity())); + assert!(inverse + .to_transform() + .approx_eq(&rigid.to_transform().inverse().unwrap())); + } + + #[test] + fn test_rigid_multiply() { + let translation = Vector3D::new(12.1, 17.8, -5.5); + let rotation = Rotation3D::unit_quaternion(0.5, -7.8, 2.2, 4.3); + let translation2 = Vector3D::new(9.3, -3.9, 1.1); + let rotation2 = Rotation3D::unit_quaternion(0.1, 0.2, 0.3, -0.4); + let rigid = RigidTransform3D::new(rotation, translation); + let rigid2 = RigidTransform3D::new(rotation2, translation2); + + assert!(rigid + .post_mul(&rigid2) + .to_transform() + .approx_eq(&rigid.to_transform().post_mul(&rigid2.to_transform()))); + assert!(rigid + .pre_mul(&rigid2) + .to_transform() + .approx_eq(&rigid.to_transform().pre_mul(&rigid2.to_transform()))); + } +} diff --git a/third_party/rust/euclid/src/rotation.rs b/third_party/rust/euclid/src/rotation.rs index a76265ebc36c..29f021f7184e 100644 --- a/third_party/rust/euclid/src/rotation.rs +++ b/third_party/rust/euclid/src/rotation.rs @@ -8,7 +8,7 @@ // except according to those terms. use approxeq::ApproxEq; -use num_traits::{Float, FloatConst, One, Zero}; +use num_traits::{Float, FloatConst, One, Zero, NumCast}; use core::fmt; use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, Sub, SubAssign}; use core::marker::PhantomData; @@ -475,8 +475,8 @@ where where T: ApproxEq, { - // TODO: we might need to relax the threshold here, because of floating point imprecision. - self.square_norm().approx_eq(&T::one()) + let eps = NumCast::from(1.0e-5).unwrap(); + self.square_norm().approx_eq_eps(&T::one(), &eps) } /// Spherical linear interpolation between this rotation and another rotation. @@ -560,7 +560,7 @@ where self.rotate_point3d(&point.to_3d()).xy() } - /// Returns the given 3d vector transformed by this rotation then projected on the xy plane. + /// Returns the given 3d vector transformed by this rotation. /// /// The input vector must be use the unit Src, and the returned point has the unit Dst. #[inline] diff --git a/third_party/rust/euclid/src/side_offsets.rs b/third_party/rust/euclid/src/side_offsets.rs index 2d5c9932e950..fb3d76cffea9 100644 --- a/third_party/rust/euclid/src/side_offsets.rs +++ b/third_party/rust/euclid/src/side_offsets.rs @@ -17,7 +17,7 @@ use core::fmt; use core::ops::Add; use core::marker::PhantomData; -/// A group of side offsets, which correspond to top/left/bottom/right for borders, padding, +/// A group of 2D side offsets, which correspond to top/left/bottom/right for borders, padding, /// and margins in CSS, optionally tagged with a unit. #[derive(EuclidMatrix)] #[repr(C)] @@ -40,7 +40,19 @@ impl fmt::Debug for TypedSideOffsets2D { } } -/// The default side offset type with no unit. +impl Default for TypedSideOffsets2D { + fn default() -> Self { + TypedSideOffsets2D { + top: Default::default(), + right: Default::default(), + bottom: Default::default(), + left: Default::default(), + _unit: PhantomData, + } + } +} + +/// The default 2D side offset type with no unit. pub type SideOffsets2D = TypedSideOffsets2D; impl TypedSideOffsets2D { diff --git a/third_party/rust/euclid/src/size.rs b/third_party/rust/euclid/src/size.rs index 044ca8ed4d0f..9aae8f7af7f7 100644 --- a/third_party/rust/euclid/src/size.rs +++ b/third_party/rust/euclid/src/size.rs @@ -13,6 +13,7 @@ use mint; use length::Length; use scale::TypedScale; use vector::{TypedVector2D, vec2, BoolVector2D}; +use vector::{TypedVector3D, vec3, BoolVector3D}; use num::*; use num_traits::{Float, NumCast, Signed}; @@ -47,6 +48,12 @@ impl fmt::Display for TypedSize2D { } } +impl Default for TypedSize2D { + fn default() -> Self { + TypedSize2D::new(Default::default(), Default::default()) + } +} + impl TypedSize2D { /// Constructor taking scalar values. pub fn new(width: T, height: T) -> Self { @@ -198,6 +205,11 @@ impl TypedSize2D { [self.width, self.height] } + #[inline] + pub fn to_tuple(&self) -> (T, T) { + (self.width, self.height) + } + #[inline] pub fn to_vector(&self) -> TypedVector2D { vec2(self.width, self.height) @@ -380,6 +392,29 @@ impl Into> for TypedSize2D { } } +impl Into<[T; 2]> for TypedSize2D { + fn into(self) -> [T; 2] { + self.to_array() + } +} + +impl From<[T; 2]> for TypedSize2D { + fn from(array: [T; 2]) -> Self { + size2(array[0], array[1]) + } +} + +impl Into<(T, T)> for TypedSize2D { + fn into(self) -> (T, T) { + self.to_tuple() + } +} + +impl From<(T, T)> for TypedSize2D { + fn from(tuple: (T, T)) -> Self { + size2(tuple.0, tuple.1) + } +} #[cfg(test)] mod size2d { @@ -441,3 +476,386 @@ mod size2d { assert_eq!(s1, s2); } } + +/// A 3d size tagged with a unit. +#[derive(EuclidMatrix)] +#[repr(C)] +pub struct TypedSize3D { + pub width: T, + pub height: T, + pub depth: T, + #[doc(hidden)] + pub _unit: PhantomData, +} + +/// Default 3d size type with no unit. +/// +/// `Size3D` provides the same methods as `TypedSize3D`. +pub type Size3D = TypedSize3D; + +impl fmt::Debug for TypedSize3D { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{:?}×{:?}×{:?}", self.width, self.height, self.depth) + } +} + +impl fmt::Display for TypedSize3D { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "({}x{}x{})", self.width, self.height, self.depth) + } +} + +impl Default for TypedSize3D { + fn default() -> Self { + TypedSize3D::new(Default::default(), Default::default(), Default::default()) + } +} + +impl TypedSize3D { + /// Constructor taking scalar values. + pub fn new(width: T, height: T, depth: T) -> Self { + TypedSize3D { + width, + height, + depth, + _unit: PhantomData, + } + } +} + +impl TypedSize3D { + /// Constructor taking scalar strongly typed lengths. + pub fn from_lengths(width: Length, height: Length, depth: Length) -> Self { + TypedSize3D::new(width.get(), height.get(), depth.get()) + } +} + +impl TypedSize3D { + /// Rounds each component to the nearest integer value. + /// + /// This behavior is preserved for negative values (unlike the basic cast). + pub fn round(&self) -> Self { + TypedSize3D::new(self.width.round(), self.height.round(), self.depth.round()) + } +} + +impl TypedSize3D { + /// Rounds each component to the smallest integer equal or greater than the original value. + /// + /// This behavior is preserved for negative values (unlike the basic cast). + pub fn ceil(&self) -> Self { + TypedSize3D::new(self.width.ceil(), self.height.ceil(), self.depth.ceil()) + } +} + +impl TypedSize3D { + /// Rounds each component to the biggest integer equal or lower than the original value. + /// + /// This behavior is preserved for negative values (unlike the basic cast). + pub fn floor(&self) -> Self { + TypedSize3D::new(self.width.floor(), self.height.floor(), self.depth.floor()) + } +} + +impl, U> Add for TypedSize3D { + type Output = Self; + fn add(self, other: Self) -> Self { + TypedSize3D::new(self.width + other.width, self.height + other.height, self.depth + other.depth) + } +} + +impl, U> Sub for TypedSize3D { + type Output = Self; + fn sub(self, other: Self) -> Self { + TypedSize3D::new(self.width - other.width, self.height - other.height, self.depth - other.depth) + } +} + +impl, U> TypedSize3D { + pub fn volume(&self) -> T { + self.width * self.height * self.depth + } +} + +impl TypedSize3D +where + T: Copy + One + Add + Sub + Mul, +{ + /// Linearly interpolate between this size and another size. + /// + /// `t` is expected to be between zero and one. + #[inline] + pub fn lerp(&self, other: Self, t: T) -> Self { + let one_t = T::one() - t; + size3( + one_t * self.width + t * other.width, + one_t * self.height + t * other.height, + one_t * self.depth + t * other.depth, + ) + } +} + +impl TypedSize3D { + pub fn is_empty_or_negative(&self) -> bool { + let zero = T::zero(); + self.width <= zero || self.height <= zero || self.depth <= zero + } +} + +impl TypedSize3D { + pub fn zero() -> Self { + TypedSize3D::new(Zero::zero(), Zero::zero(), Zero::zero()) + } +} + +impl Zero for TypedSize3D { + fn zero() -> Self { + TypedSize3D::new(Zero::zero(), Zero::zero(), Zero::zero()) + } +} + +impl, U> Mul for TypedSize3D { + type Output = Self; + #[inline] + fn mul(self, scale: T) -> Self { + TypedSize3D::new(self.width * scale, self.height * scale, self.depth * scale) + } +} + +impl, U> Div for TypedSize3D { + type Output = Self; + #[inline] + fn div(self, scale: T) -> Self { + TypedSize3D::new(self.width / scale, self.height / scale, self.depth / scale) + } +} + +impl, U1, U2> Mul> for TypedSize3D { + type Output = TypedSize3D; + #[inline] + fn mul(self, scale: TypedScale) -> TypedSize3D { + TypedSize3D::new(self.width * scale.get(), self.height * scale.get(), self.depth * scale.get()) + } +} + +impl, U1, U2> Div> for TypedSize3D { + type Output = TypedSize3D; + #[inline] + fn div(self, scale: TypedScale) -> TypedSize3D { + TypedSize3D::new(self.width / scale.get(), self.height / scale.get(), self.depth / scale.get()) + } +} + +impl TypedSize3D { + /// Returns self.width as a Length carrying the unit. + #[inline] + pub fn width_typed(&self) -> Length { + Length::new(self.width) + } + + /// Returns self.height as a Length carrying the unit. + #[inline] + pub fn height_typed(&self) -> Length { + Length::new(self.height) + } + + /// Returns self.depth as a Length carrying the unit. + #[inline] + pub fn depth_typed(&self) -> Length { + Length::new(self.depth) + } + + #[inline] + pub fn to_array(&self) -> [T; 3] { + [self.width, self.height, self.depth] + } + + #[inline] + pub fn to_vector(&self) -> TypedVector3D { + vec3(self.width, self.height, self.depth) + } + + /// Drop the units, preserving only the numeric value. + pub fn to_untyped(&self) -> Size3D { + TypedSize3D::new(self.width, self.height, self.depth) + } + + /// Tag a unitless value with units. + pub fn from_untyped(p: &Size3D) -> Self { + TypedSize3D::new(p.width, p.height, p.depth) + } +} + +impl TypedSize3D { + /// Cast from one numeric representation to another, preserving the units. + /// + /// When casting from floating point to integer coordinates, the decimals are truncated + /// as one would expect from a simple cast, but this behavior does not always make sense + /// geometrically. Consider using `round()`, `ceil()` or `floor()` before casting. + pub fn cast(&self) -> TypedSize3D { + self.try_cast().unwrap() + } + + /// Fallible cast from one numeric representation to another, preserving the units. + /// + /// When casting from floating point to integer coordinates, the decimals are truncated + /// as one would expect from a simple cast, but this behavior does not always make sense + /// geometrically. Consider using `round()`, `ceil()` or `floor()` before casting. + pub fn try_cast(&self) -> Option> { + match (NumCast::from(self.width), NumCast::from(self.height), NumCast::from(self.depth)) { + (Some(w), Some(h), Some(d)) => Some(TypedSize3D::new(w, h, d)), + _ => None, + } + } + + // Convenience functions for common casts + + /// Cast into an `f32` size. + pub fn to_f32(&self) -> TypedSize3D { + self.cast() + } + + /// Cast into an `f64` size. + pub fn to_f64(&self) -> TypedSize3D { + self.cast() + } + + /// Cast into an `uint` size, truncating decimals if any. + /// + /// When casting from floating point sizes, it is worth considering whether + /// to `round()`, `ceil()` or `floor()` before the cast in order to obtain + /// the desired conversion behavior. + pub fn to_usize(&self) -> TypedSize3D { + self.cast() + } + + /// Cast into an `u32` size, truncating decimals if any. + /// + /// When casting from floating point sizes, it is worth considering whether + /// to `round()`, `ceil()` or `floor()` before the cast in order to obtain + /// the desired conversion behavior. + pub fn to_u32(&self) -> TypedSize3D { + self.cast() + } + + /// Cast into an `i32` size, truncating decimals if any. + /// + /// When casting from floating point sizes, it is worth considering whether + /// to `round()`, `ceil()` or `floor()` before the cast in order to obtain + /// the desired conversion behavior. + pub fn to_i32(&self) -> TypedSize3D { + self.cast() + } + + /// Cast into an `i64` size, truncating decimals if any. + /// + /// When casting from floating point sizes, it is worth considering whether + /// to `round()`, `ceil()` or `floor()` before the cast in order to obtain + /// the desired conversion behavior. + pub fn to_i64(&self) -> TypedSize3D { + self.cast() + } +} + +impl TypedSize3D +where + T: Signed, +{ + pub fn abs(&self) -> Self { + size3(self.width.abs(), self.height.abs(), self.depth.abs()) + } + + pub fn is_positive(&self) -> bool { + self.width.is_positive() && self.height.is_positive() && self.depth.is_positive() + } +} + +impl TypedSize3D { + pub fn greater_than(&self, other: &Self) -> BoolVector3D { + BoolVector3D { + x: self.width > other.width, + y: self.height > other.height, + z: self.depth > other.depth, + } + } + + pub fn lower_than(&self, other: &Self) -> BoolVector3D { + BoolVector3D { + x: self.width < other.width, + y: self.height < other.height, + z: self.depth < other.depth, + } + } +} + + +impl TypedSize3D { + pub fn equal(&self, other: &Self) -> BoolVector3D { + BoolVector3D { + x: self.width == other.width, + y: self.height == other.height, + z: self.depth == other.depth, + } + } + + pub fn not_equal(&self, other: &Self) -> BoolVector3D { + BoolVector3D { + x: self.width != other.width, + y: self.height != other.height, + z: self.depth != other.depth, + } + } +} + +impl TypedSize3D { + #[inline] + pub fn min(self, other: Self) -> Self { + size3( + self.width.min(other.width), + self.height.min(other.height), + self.depth.min(other.depth), + ) + } + + #[inline] + pub fn max(self, other: Self) -> Self { + size3( + self.width.max(other.width), + self.height.max(other.height), + self.depth.max(other.depth), + ) + } + + #[inline] + pub fn clamp(&self, start: Self, end: Self) -> Self { + self.max(start).min(end) + } +} + + +/// Shorthand for `TypedSize3D::new(w, h, d)`. +pub fn size3(w: T, h: T, d: T) -> TypedSize3D { + TypedSize3D::new(w, h, d) +} + +#[cfg(feature = "mint")] +impl From> for TypedSize3D { + fn from(v: mint::Vector3) -> Self { + TypedSize3D { + width: v.x, + height: v.y, + depth: v.z, + _unit: PhantomData, + } + } +} +#[cfg(feature = "mint")] +impl Into> for TypedSize3D { + fn into(self) -> mint::Vector3 { + mint::Vector3 { + x: self.width, + y: self.height, + z: self.depth, + } + } +} diff --git a/third_party/rust/euclid/src/transform2d.rs b/third_party/rust/euclid/src/transform2d.rs index 789e86674218..5e6af3d7f374 100644 --- a/third_party/rust/euclid/src/transform2d.rs +++ b/third_party/rust/euclid/src/transform2d.rs @@ -35,6 +35,10 @@ use num_traits::NumCast; /// A pre-transformation corresponds to adding an operation that is applied before /// the rest of the transformation, while a post-transformation adds an operation /// that is applied after. +/// +/// These transforms are for working with _row vectors_, so the matrix math for transforming +/// a vector is `v * T`. If your library is using column vectors, use `row_major` functions when you +/// are asked for `column_major` representations and vice versa. #[repr(C)] #[derive(EuclidMatrix)] pub struct TypedTransform2D { @@ -50,6 +54,10 @@ pub type Transform2D = TypedTransform2D; impl TypedTransform2D { /// Create a transform specifying its matrix elements in row-major order. + /// + /// Beware: This library is written with the assumption that row vectors + /// are being used. If your matrices use column vectors (i.e. transforming a vector + /// is `T * v`), then please use `column_major` pub fn row_major(m11: T, m12: T, m21: T, m22: T, m31: T, m32: T) -> Self { TypedTransform2D { m11, m12, @@ -60,6 +68,10 @@ impl TypedTransform2D { } /// Create a transform specifying its matrix elements in column-major order. + /// + /// Beware: This library is written with the assumption that row vectors + /// are being used. If your matrices use column vectors (i.e. transforming a vector + /// is `T * v`), then please use `row_major` pub fn column_major(m11: T, m21: T, m31: T, m12: T, m22: T, m32: T) -> Self { TypedTransform2D { m11, m12, @@ -71,6 +83,10 @@ impl TypedTransform2D { /// Returns an array containing this transform's terms in row-major order (the order /// in which the transform is actually laid out in memory). + /// + /// Beware: This library is written with the assumption that row vectors + /// are being used. If your matrices use column vectors (i.e. transforming a vector + /// is `T * v`), then please use `to_column_major_array` pub fn to_row_major_array(&self) -> [T; 6] { [ self.m11, self.m12, @@ -80,6 +96,10 @@ impl TypedTransform2D { } /// Returns an array containing this transform's terms in column-major order. + /// + /// Beware: This library is written with the assumption that row vectors + /// are being used. If your matrices use column vectors (i.e. transforming a vector + /// is `T * v`), then please use `to_row_major_array` pub fn to_column_major_array(&self) -> [T; 6] { [ self.m11, self.m21, self.m31, @@ -91,6 +111,10 @@ impl TypedTransform2D { /// as arrays. /// /// This is a convenience method to interface with other libraries like glium. + /// + /// Beware: This library is written with the assumption that row vectors + /// are being used. If your matrices use column vectors (i.e. transforming a vector + /// is `T * v`), this will return column major arrays. pub fn to_row_arrays(&self) -> [[T; 2]; 3] { [ [self.m11, self.m12], @@ -100,6 +124,10 @@ impl TypedTransform2D { } /// Creates a transform from an array of 6 elements in row-major order. + /// + /// Beware: This library is written with the assumption that row vectors + /// are being used. If your matrices use column vectors (i.e. transforming a vector + /// is `T * v`), please provide a column major array. pub fn from_row_major_array(array: [T; 6]) -> Self { Self::row_major( array[0], array[1], @@ -109,6 +137,10 @@ impl TypedTransform2D { } /// Creates a transform from 3 rows of 2 elements (row-major order). + /// + /// Beware: This library is written with the assumption that row vectors + /// are being used. If your matrices use column vectors (i.e. transforming a vector + /// is `T * v`), please provide a column major array. pub fn from_row_arrays(array: [[T; 2]; 3]) -> Self { Self::row_major( array[0][0], array[0][1], @@ -194,6 +226,8 @@ where T: Copy + Clone + /// Returns the multiplication of the two matrices such that mat's transformation /// applies after self's transformation. + /// + /// Assuming row vectors, this is equivalent to self * mat #[cfg_attr(feature = "unstable", must_use)] pub fn post_mul(&self, mat: &TypedTransform2D) -> TypedTransform2D { TypedTransform2D::row_major( @@ -208,6 +242,8 @@ where T: Copy + Clone + /// Returns the multiplication of the two matrices such that mat's transformation /// applies before self's transformation. + /// + /// Assuming row vectors, this is equivalent to mat * self #[cfg_attr(feature = "unstable", must_use)] pub fn pre_mul(&self, mat: &TypedTransform2D) -> TypedTransform2D { mat.post_mul(self) @@ -286,6 +322,8 @@ where T: Copy + Clone + } /// Returns the given point transformed by this transform. + /// + /// Assuming row vectors, this is equivalent to `p * self` #[inline] #[cfg_attr(feature = "unstable", must_use)] pub fn transform_point(&self, point: &TypedPoint2D) -> TypedPoint2D { @@ -294,6 +332,8 @@ where T: Copy + Clone + } /// Returns the given vector transformed by this matrix. + /// + /// Assuming row vectors, this is equivalent to `v * self` #[inline] #[cfg_attr(feature = "unstable", must_use)] pub fn transform_vector(&self, vec: &TypedVector2D) -> TypedVector2D { diff --git a/third_party/rust/euclid/src/transform3d.rs b/third_party/rust/euclid/src/transform3d.rs index a681732beb87..13c6f71b440a 100644 --- a/third_party/rust/euclid/src/transform3d.rs +++ b/third_party/rust/euclid/src/transform3d.rs @@ -37,6 +37,10 @@ use num_traits::NumCast; /// A pre-transformation corresponds to adding an operation that is applied before /// the rest of the transformation, while a post-transformation adds an operation /// that is applied after. +/// +/// These transforms are for working with _row vectors_, so the matrix math for transforming +/// a vector is `v * T`. If your library is using column vectors, use `row_major` functions when you +/// are asked for `column_major` representations and vice versa. #[derive(EuclidMatrix)] #[repr(C)] pub struct TypedTransform3D { @@ -56,6 +60,10 @@ impl TypedTransform3D { /// /// For example, the translation terms m41, m42, m43 on the last row with the /// row-major convention) are the 13rd, 14th and 15th parameters. + /// + /// Beware: This library is written with the assumption that row vectors + /// are being used. If your matrices use column vectors (i.e. transforming a vector + /// is `T * v`), then please use `column_major` #[inline] #[cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))] pub fn row_major( @@ -77,6 +85,10 @@ impl TypedTransform3D { /// /// For example, the translation terms m41, m42, m43 on the last column with the /// column-major convention) are the 4th, 8th and 12nd parameters. + /// + /// Beware: This library is written with the assumption that row vectors + /// are being used. If your matrices use column vectors (i.e. transforming a vector + /// is `T * v`), then please use `row_major` #[inline] #[cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))] pub fn column_major( @@ -256,6 +268,8 @@ where T: Copy + Clone + /// Returns the multiplication of the two matrices such that mat's transformation /// applies after self's transformation. + /// + /// Assuming row vectors, this is equivalent to self * mat pub fn post_mul(&self, mat: &TypedTransform3D) -> TypedTransform3D { TypedTransform3D::row_major( self.m11 * mat.m11 + self.m12 * mat.m21 + self.m13 * mat.m31 + self.m14 * mat.m41, @@ -279,6 +293,8 @@ where T: Copy + Clone + /// Returns the multiplication of the two matrices such that mat's transformation /// applies before self's transformation. + /// + /// Assuming row vectors, this is equivalent to mat * self pub fn pre_mul(&self, mat: &TypedTransform3D) -> TypedTransform3D { mat.post_mul(self) } @@ -410,6 +426,8 @@ where T: Copy + Clone + /// Returns the homogeneous vector corresponding to the transformed 2d point. /// /// The input point must be use the unit Src, and the returned point has the unit Dst. + /// + /// Assuming row vectors, this is equivalent to `p * self` #[inline] pub fn transform_point2d_homogeneous( &self, p: &TypedPoint2D @@ -427,6 +445,7 @@ where T: Copy + Clone + /// /// The input point must be use the unit Src, and the returned point has the unit Dst. /// + /// Assuming row vectors, this is equivalent to `p * self` #[inline] pub fn transform_point2d(&self, p: &TypedPoint2D) -> Option> { //Note: could use `transform_point2d_homogeneous()` but it would waste the calculus of `z` @@ -444,6 +463,8 @@ where T: Copy + Clone + /// Returns the given 2d vector transformed by this matrix. /// /// The input point must be use the unit Src, and the returned point has the unit Dst. + /// + /// Assuming row vectors, this is equivalent to `v * self` #[inline] pub fn transform_vector2d(&self, v: &TypedVector2D) -> TypedVector2D { vec2( @@ -455,6 +476,8 @@ where T: Copy + Clone + /// Returns the homogeneous vector corresponding to the transformed 3d point. /// /// The input point must be use the unit Src, and the returned point has the unit Dst. + /// + /// Assuming row vectors, this is equivalent to `p * self` #[inline] pub fn transform_point3d_homogeneous( &self, p: &TypedPoint3D @@ -471,6 +494,8 @@ where T: Copy + Clone + /// or `None` otherwise. /// /// The input point must be use the unit Src, and the returned point has the unit Dst. + /// + /// Assuming row vectors, this is equivalent to `p * self` #[inline] pub fn transform_point3d(&self, p: &TypedPoint3D) -> Option> { self.transform_point3d_homogeneous(p).to_point3d() @@ -479,6 +504,8 @@ where T: Copy + Clone + /// Returns the given 3d vector transformed by this matrix. /// /// The input point must be use the unit Src, and the returned point has the unit Dst. + /// + /// Assuming row vectors, this is equivalent to `v * self` #[inline] pub fn transform_vector3d(&self, v: &TypedVector3D) -> TypedVector3D { vec3( @@ -664,6 +691,10 @@ where T: Copy + Clone + impl TypedTransform3D { /// Returns an array containing this transform's terms in row-major order (the order /// in which the transform is actually laid out in memory). + /// + /// Beware: This library is written with the assumption that row vectors + /// are being used. If your matrices use column vectors (i.e. transforming a vector + /// is `T * v`), then please use `to_column_major_array` pub fn to_row_major_array(&self) -> [T; 16] { [ self.m11, self.m12, self.m13, self.m14, @@ -674,6 +705,10 @@ impl TypedTransform3D { } /// Returns an array containing this transform's terms in column-major order. + /// + /// Beware: This library is written with the assumption that row vectors + /// are being used. If your matrices use column vectors (i.e. transforming a vector + /// is `T * v`), then please use `to_row_major_array` pub fn to_column_major_array(&self) -> [T; 16] { [ self.m11, self.m21, self.m31, self.m41, @@ -687,6 +722,10 @@ impl TypedTransform3D { /// as arrays. /// /// This is a convenience method to interface with other libraries like glium. + /// + /// Beware: This library is written with the assumption that row vectors + /// are being used. If your matrices use column vectors (i.e. transforming a vector + /// is `T * v`), then please use `to_column_arrays` pub fn to_row_arrays(&self) -> [[T; 4]; 4] { [ [self.m11, self.m12, self.m13, self.m14], @@ -700,6 +739,10 @@ impl TypedTransform3D { /// or 4 rows in column-major order) as arrays. /// /// This is a convenience method to interface with other libraries like glium. + /// + /// Beware: This library is written with the assumption that row vectors + /// are being used. If your matrices use column vectors (i.e. transforming a vector + /// is `T * v`), then please use `to_row_arrays` pub fn to_column_arrays(&self) -> [[T; 4]; 4] { [ [self.m11, self.m21, self.m31, self.m41], @@ -710,6 +753,10 @@ impl TypedTransform3D { } /// Creates a transform from an array of 16 elements in row-major order. + /// + /// Beware: This library is written with the assumption that row vectors + /// are being used. If your matrices use column vectors (i.e. transforming a vector + /// is `T * v`), please provide column-major data to this function. pub fn from_array(array: [T; 16]) -> Self { Self::row_major( array[0], array[1], array[2], array[3], @@ -720,6 +767,10 @@ impl TypedTransform3D { } /// Creates a transform from 4 rows of 4 elements (row-major order). + /// + /// Beware: This library is written with the assumption that row vectors + /// are being used. If your matrices use column vectors (i.e. transforming a vector + /// is `T * v`), please provide column-major data to tis function. pub fn from_row_arrays(array: [[T; 4]; 4]) -> Self { Self::row_major( array[0][0], array[0][1], array[0][2], array[0][3], diff --git a/third_party/rust/euclid/src/translation.rs b/third_party/rust/euclid/src/translation.rs index cf70c2418a48..9f3ca047b3a0 100644 --- a/third_party/rust/euclid/src/translation.rs +++ b/third_party/rust/euclid/src/translation.rs @@ -63,6 +63,11 @@ where pub fn to_array(&self) -> [T; 2] { [self.x, self.y] } + + #[inline] + pub fn to_tuple(&self) -> (T, T) { + (self.x, self.y) + } } impl TypedTranslation2D @@ -264,6 +269,11 @@ where pub fn to_array(&self) -> [T; 3] { [self.x, self.y, self.z] } + + #[inline] + pub fn to_tuple(&self) -> (T, T, T) { + (self.x, self.y, self.z) + } } impl TypedTranslation3D diff --git a/third_party/rust/euclid/src/vector.rs b/third_party/rust/euclid/src/vector.rs index 91700800e3c6..ec8765743de4 100644 --- a/third_party/rust/euclid/src/vector.rs +++ b/third_party/rust/euclid/src/vector.rs @@ -15,6 +15,8 @@ use mint; use point::{TypedPoint2D, TypedPoint3D, point2, point3}; use size::{TypedSize2D, size2}; use scale::TypedScale; +use transform2d::TypedTransform2D; +use transform3d::TypedTransform3D; use trig::Trig; use Angle; use num::*; @@ -66,6 +68,12 @@ impl fmt::Display for TypedVector2D { } } +impl Default for TypedVector2D { + fn default() -> Self { + TypedVector2D::new(Default::default(), Default::default()) + } +} + impl TypedVector2D { /// Constructor taking scalar values directly. #[inline] @@ -135,10 +143,39 @@ impl TypedVector2D { vec2(p.x, p.y) } + /// Cast the unit + #[inline] + pub fn cast_unit(&self) -> TypedVector2D { + vec2(self.x, self.y) + } + #[inline] pub fn to_array(&self) -> [T; 2] { [self.x, self.y] } + + #[inline] + pub fn to_tuple(&self) -> (T, T) { + (self.x, self.y) + } +} + +impl TypedVector2D +where + T: Copy + + Clone + + Add + + Mul + + Div + + Sub + + Trig + + PartialOrd + + One + + Zero { + #[inline] + pub fn to_transform(&self) -> TypedTransform2D { + TypedTransform2D::create_translation(self.x, self.y) + } } impl TypedVector2D @@ -462,6 +499,18 @@ impl From<[T; 2]> for TypedVector2D { } } +impl Into<(T, T)> for TypedVector2D { + fn into(self) -> (T, T) { + self.to_tuple() + } +} + +impl From<(T, T)> for TypedVector2D { + fn from(tuple: (T, T)) -> Self { + vec2(tuple.0, tuple.1) + } +} + impl TypedVector2D where T: Signed, @@ -500,6 +549,11 @@ impl TypedVector3D { pub fn to_array_4d(&self) -> [T; 4] { [self.x, self.y, self.z, Zero::zero()] } + + #[inline] + pub fn to_tuple_4d(&self) -> (T, T, T, T) { + (self.x, self.y, self.z, Zero::zero()) + } } impl fmt::Debug for TypedVector3D { @@ -514,6 +568,12 @@ impl fmt::Display for TypedVector3D { } } +impl Default for TypedVector3D { + fn default() -> Self { + TypedVector3D::new(Default::default(), Default::default(), Default::default()) + } +} + impl TypedVector3D { /// Constructor taking scalar values directly. #[inline] @@ -583,6 +643,11 @@ impl TypedVector3D { [self.x, self.y, self.z] } + #[inline] + pub fn to_tuple(&self) -> (T, T, T) { + (self.x, self.y, self.z) + } + /// Drop the units, preserving only the numeric value. #[inline] pub fn to_untyped(&self) -> Vector3D { @@ -602,6 +667,25 @@ impl TypedVector3D { } } +impl TypedVector3D +where + T: Copy + + Clone + + Add + + Mul + + Div + + Sub + + Trig + + PartialOrd + + One + + Zero + + Neg { + #[inline] + pub fn to_transform(&self) -> TypedTransform3D { + TypedTransform3D::create_translation(self.x, self.y, self.z) + } +} + impl + Add + Sub + Copy, U> TypedVector3D { // Dot product. @@ -930,6 +1014,18 @@ impl From<[T; 3]> for TypedVector3D { } } +impl Into<(T, T, T)> for TypedVector3D { + fn into(self) -> (T, T, T) { + self.to_tuple() + } +} + +impl From<(T, T, T)> for TypedVector3D { + fn from(tuple: (T, T, T)) -> Self { + vec3(tuple.0, tuple.1, tuple.2) + } +} + impl TypedVector3D where T: Signed, diff --git a/third_party/rust/serde_derive/.cargo-checksum.json b/third_party/rust/serde_derive/.cargo-checksum.json index 62ec85a637cb..2931d63e29db 100644 --- a/third_party/rust/serde_derive/.cargo-checksum.json +++ b/third_party/rust/serde_derive/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"071ea0d1ef1e899f01b0e90383b7dfefdf1b23c733444c59815ce345e7833054","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"11f6eec1a694070311f8ff191c53e67b90bf1d5064f32d684a1b73b1c3264ac1","crates-io.md":"131dee2d4beaf83485aed22942b98815ef65af9bcfb65f02b5b90c59b8bc7b8b","src/bound.rs":"47b4018d54220862c2546589fe3cbccdd72c5d90438c265c258c1a2ee98e9210","src/de.rs":"09ba5a4cab60dfc713ea66f69d1989786a913e060f1ec6f9b701e83f37448931","src/dummy.rs":"413f639118681cecff6188e790c88636e34dd8e1b247bbbaa7b6a121b5cf6921","src/fragment.rs":"5819ac5b16f5945c05ce47c3370745f2e73deb415367ae6afbd8208867f611d2","src/internals/ast.rs":"64cd449a627a3489053407735f0d1de669272d879a75afc66051e323a1c1ebd4","src/internals/attr.rs":"f95eb8481822f4b5eca5e28483469c020d73335d60980cb20e1c28a073b90f52","src/internals/case.rs":"b2024f414f5d832bafa53b9ae7924b2d43a29175b19bb3da36f15c9071666558","src/internals/check.rs":"d101f08b2bd007602c4a7b3f6ae2d4cb9fbe0c179cde55809a666ed4a7043a12","src/internals/ctxt.rs":"ceb74c96802f89de896a30b774b49d4954d6c3344596cbbc1ff8fad2ac754fe1","src/internals/mod.rs":"8e363739bbfcd43bcaedd1746b2d17cebd5964167c145bd0db473f0ff4521edc","src/lib.rs":"fd6883d899ea98448aee074374388fdfd8792363928cc1ddd3812737c5921a76","src/pretend.rs":"ea5aa1b338038ce1791cef34fd20091abb062cd61c0384ac931d0069413a5302","src/ser.rs":"843b2a66a17511640c4e5ebd08e16b8f58f9772c7a8283e1bb2f043b302f21be","src/try.rs":"b9a10c8690d442a57fc7097d42c9a4f13034c7b4a30b7eb02d538fdbf8ae0a8d"},"package":null} \ No newline at end of file +{"files":{"Cargo.toml":"e32cf0f1999d39d32e222b28b26ccc431533204f6ae4f96afc55f0231900126b","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"11f6eec1a694070311f8ff191c53e67b90bf1d5064f32d684a1b73b1c3264ac1","crates-io.md":"131dee2d4beaf83485aed22942b98815ef65af9bcfb65f02b5b90c59b8bc7b8b","src/bound.rs":"346f20898b86432bad7ea86207b0b395d52fe804cb4b0f9805ba6f3ff58f9cd0","src/de.rs":"c7fba9a1206b11a17bd6445a9d6945f5171c7e81587f90aaf26732f50126dad7","src/dummy.rs":"413f639118681cecff6188e790c88636e34dd8e1b247bbbaa7b6a121b5cf6921","src/fragment.rs":"5819ac5b16f5945c05ce47c3370745f2e73deb415367ae6afbd8208867f611d2","src/internals/ast.rs":"b0a791275ea3d6f0e7b698e0758757dc6a4a5ce25ae45a9adfe70c1ac878fb34","src/internals/attr.rs":"f95eb8481822f4b5eca5e28483469c020d73335d60980cb20e1c28a073b90f52","src/internals/case.rs":"b2024f414f5d832bafa53b9ae7924b2d43a29175b19bb3da36f15c9071666558","src/internals/check.rs":"5beb3d32fcdf689dfce60eb4d5cf8f0167dcde3286e8075f8e40cb4aa714b8ad","src/internals/ctxt.rs":"ceb74c96802f89de896a30b774b49d4954d6c3344596cbbc1ff8fad2ac754fe1","src/internals/mod.rs":"8e363739bbfcd43bcaedd1746b2d17cebd5964167c145bd0db473f0ff4521edc","src/lib.rs":"fd6883d899ea98448aee074374388fdfd8792363928cc1ddd3812737c5921a76","src/pretend.rs":"24c7c4168cf176e77e718627ab81c1055481187d1551282f20416c01af895891","src/ser.rs":"1ee1499c317f5c8fadc21cb60ee9f114a748a17da4a52219ed03ec7eb3f894a8","src/try.rs":"b9a10c8690d442a57fc7097d42c9a4f13034c7b4a30b7eb02d538fdbf8ae0a8d"},"package":"beed18e6f5175aef3ba670e57c60ef3b1b74d250d962a26604bff4c80e970dd4"} \ No newline at end of file diff --git a/third_party/rust/serde_derive/Cargo.toml b/third_party/rust/serde_derive/Cargo.toml index 3a95f696d330..f9f2c2da20ac 100644 --- a/third_party/rust/serde_derive/Cargo.toml +++ b/third_party/rust/serde_derive/Cargo.toml @@ -1,32 +1,48 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + [package] name = "serde_derive" -version = "1.0.88" # remember to update html_root_url +version = "1.0.88" authors = ["Erick Tryzelaar ", "David Tolnay "] -license = "MIT/Apache-2.0" +include = ["Cargo.toml", "src/**/*.rs", "crates-io.md", "README.md", "LICENSE-APACHE", "LICENSE-MIT"] description = "Macros 1.1 implementation of #[derive(Serialize, Deserialize)]" homepage = "https://serde.rs" -repository = "https://github.com/serde-rs/serde" documentation = "https://serde.rs/derive.html" -keywords = ["serde", "serialization", "no_std"] readme = "crates-io.md" -include = ["Cargo.toml", "src/**/*.rs", "crates-io.md", "README.md", "LICENSE-APACHE", "LICENSE-MIT"] - -[badges] -travis-ci = { repository = "serde-rs/serde" } -appveyor = { repository = "serde-rs/serde" } - -[features] -default = [] -deserialize_in_place = [] +keywords = ["serde", "serialization", "no_std"] +license = "MIT/Apache-2.0" +repository = "https://github.com/serde-rs/serde" [lib] name = "serde_derive" proc-macro = true +[dependencies.proc-macro2] +version = "0.4" -[dependencies] -proc-macro2 = "0.4" -quote = "0.6.3" -syn = { version = "0.15.22", features = ["visit", "extra-traits"] } +[dependencies.quote] +version = "0.6.3" -[dev-dependencies] -serde = { version = "1.0", path = "../serde" } +[dependencies.syn] +version = "0.15.22" +features = ["visit"] +[dev-dependencies.serde] +version = "1.0" + +[features] +default = [] +deserialize_in_place = [] +[badges.appveyor] +repository = "serde-rs/serde" + +[badges.travis-ci] +repository = "serde-rs/serde" diff --git a/third_party/rust/serde_derive/src/bound.rs b/third_party/rust/serde_derive/src/bound.rs index b67753e66ee0..7257862de887 100644 --- a/third_party/rust/serde_derive/src/bound.rs +++ b/third_party/rust/serde_derive/src/bound.rs @@ -64,7 +64,7 @@ pub fn with_where_predicates_from_variants( from_variant: fn(&attr::Variant) -> Option<&[syn::WherePredicate]>, ) -> syn::Generics { let variants = match cont.data { - Data::Enum(_, ref variants) => variants, + Data::Enum(ref variants) => variants, Data::Struct(_, _) => { return generics.clone(); } @@ -161,7 +161,7 @@ pub fn with_bound( associated_type_usage: Vec::new(), }; match cont.data { - Data::Enum(_, ref variants) => { + Data::Enum(ref variants) => { for variant in variants.iter() { let relevant_fields = variant .fields diff --git a/third_party/rust/serde_derive/src/de.rs b/third_party/rust/serde_derive/src/de.rs index 773d3b753718..c43d1bb73101 100644 --- a/third_party/rust/serde_derive/src/de.rs +++ b/third_party/rust/serde_derive/src/de.rs @@ -11,10 +11,6 @@ use internals::ast::{Container, Data, Field, Style, Variant}; use internals::{attr, Ctxt, Derive}; use pretend; -#[cfg(feature = "deserialize_in_place")] -use internals::ast::Repr; - - use std::collections::BTreeSet; pub fn expand_derive_deserialize(input: &syn::DeriveInput) -> Result> { @@ -99,7 +95,6 @@ fn precondition_no_de_lifetime(cx: &Ctxt, cont: &Container) { } } -#[derive(Clone)] struct Parameters { /// Name of the type the `derive` is on. local: syn::Ident, @@ -214,7 +209,6 @@ fn requires_default(field: &attr::Field, _variant: Option<&attr::Variant>) -> bo } } -#[derive(Clone)] enum BorrowedLifetimes { Borrowed(BTreeSet), Static, @@ -271,7 +265,7 @@ fn deserialize_body(cont: &Container, params: &Parameters) -> Fragment { deserialize_from(type_from) } else if let attr::Identifier::No = cont.attrs.identifier() { match cont.data { - Data::Enum(_, ref variants) => deserialize_enum(params, variants, &cont.attrs), + Data::Enum(ref variants) => deserialize_enum(params, variants, &cont.attrs), Data::Struct(Style::Struct, ref fields) => { deserialize_struct(None, params, fields, &cont.attrs, None, &Untagged::No) } @@ -282,7 +276,7 @@ fn deserialize_body(cont: &Container, params: &Parameters) -> Fragment { } } else { match cont.data { - Data::Enum(_, ref variants) => { + Data::Enum(ref variants) => { deserialize_custom_identifier(params, variants, &cont.attrs) } Data::Struct(_, _) => unreachable!("checked in serde_derive_internals"), @@ -319,14 +313,7 @@ fn deserialize_in_place_body(cont: &Container, params: &Parameters) -> Option { deserialize_tuple_in_place(None, params, fields, &cont.attrs, None) } - Data::Enum(ref repr, ref variants) => { - if let Some(x) = deserialize_enum_in_place(params, repr, variants, &cont.attrs) { - x - } else { - return None; - } - } - Data::Struct(Style::Unit, _) => { + Data::Enum(_) | Data::Struct(Style::Unit, _) => { return None; } }; @@ -354,7 +341,7 @@ fn deserialize_in_place_body(_cont: &Container, _params: &Parameters) -> Option< fn deserialize_transparent(cont: &Container, params: &Parameters) -> Fragment { let fields = match cont.data { Data::Struct(_, ref fields) => fields, - Data::Enum(_, _) => unreachable!(), + Data::Enum(_) => unreachable!(), }; let this = ¶ms.this; @@ -554,28 +541,19 @@ fn deserialize_tuple_in_place( None }; - let visit_seq = Stmts(deserialize_seq_in_place(params, fields, is_enum, cattrs, &expecting)); + let visit_seq = Stmts(deserialize_seq_in_place(params, fields, cattrs, &expecting)); - let visitor_expr = if is_enum { - quote! { - __Visitor { - place: this, - lifetime: _serde::export::PhantomData, - } - } - } else { - quote! { - __Visitor { - place: __place, - lifetime: _serde::export::PhantomData, - } + let visitor_expr = quote! { + __Visitor { + place: __place, + lifetime: _serde::export::PhantomData, } }; let dispatch = if let Some(deserializer) = deserializer { quote!(_serde::Deserializer::deserialize_tuple(#deserializer, #nfields, #visitor_expr)) } else if is_enum { - quote!(try!(_serde::de::VariantAccess::tuple_variant(__variant, #nfields, #visitor_expr))) + quote!(_serde::de::VariantAccess::tuple_variant(__variant, #nfields, #visitor_expr)) } else if nfields == 1 { let type_name = cattrs.name().deserialize_name(); quote!(_serde::Deserializer::deserialize_newtype_struct(__deserializer, #type_name, #visitor_expr)) @@ -732,11 +710,9 @@ fn deserialize_seq( fn deserialize_seq_in_place( params: &Parameters, fields: &[Field], - _increment_fields: bool, // FIXME: Not needed anymore? cattrs: &attr::Container, expecting: &str, ) -> Fragment { - // For enums there's a secret `tag` field at the start which we shouldn't touch, let deserialized_count = fields .iter() .filter(|field| !field.attrs.skip_deserializing()) @@ -1063,7 +1039,7 @@ fn deserialize_struct_in_place( None => format!("struct {}", params.type_name()), }; - let visit_seq = Stmts(deserialize_seq_in_place(params, fields, false, cattrs, &expecting)); + let visit_seq = Stmts(deserialize_seq_in_place(params, fields, cattrs, &expecting)); let (field_visitor, fields_stmt, visit_map) = deserialize_struct_as_struct_in_place_visitor(params, fields, cattrs); @@ -1164,19 +1140,6 @@ fn deserialize_enum( } } -#[cfg(feature = "deserialize_in_place")] -fn deserialize_enum_in_place( - params: &Parameters, - repr: &Repr, - variants: &[Variant], - cattrs: &attr::Container, -) -> Option { - match *cattrs.tag() { - attr::TagType::External => deserialize_externally_tagged_enum_in_place(params, repr, variants, cattrs), - _ => None, - } -} - fn prepare_enum_variant_enum( variants: &[Variant], cattrs: &attr::Container, @@ -1306,259 +1269,6 @@ fn deserialize_externally_tagged_enum( } } -#[cfg(feature = "deserialize_in_place")] -fn deserialize_externally_tagged_enum_in_place( - params: &Parameters, - repr: &Repr, - variants: &[Variant], - cattrs: &attr::Container, -) -> Option { - let int_repr = repr.get_stable_rust_enum_layout().map(|int_repr| { - let int_repr = Ident::new(int_repr, Span::call_site()); - quote!(#[repr(#int_repr)]) - }); - - let unit_variant = variants.iter().position(|variant| is_unit(variant)); - let non_unit_variant = variants.iter().enumerate().find(|&(_, variant)| !is_unit(variant)); - - // We need an int_repr, unit variant, and a non-unit variant to proceed - if int_repr.is_none() || unit_variant.is_none() || non_unit_variant.is_none() { - return None; - } - - let unit_index = unit_variant.unwrap(); - let (non_unit_index, non_unit_variant) = non_unit_variant.unwrap(); - let int_repr = int_repr.unwrap(); - - let this = ¶ms.this; - let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = split_with_de_lifetime(params,); - let delife = params.borrowed.de_lifetime(); - - let type_name = cattrs.name().deserialize_name(); - - let expecting = format!("enum {}", params.type_name()); - - let variant_names_idents: Vec<_> = variants - .iter() - .enumerate() - .filter(|&(_, variant)| !variant.attrs.skip_deserializing()) - .map(|(i, variant)| { - ( - variant.attrs.name().deserialize_name(), - field_i(i), - variant.attrs.aliases(), - ) - }) - .collect(); - - let variants_stmt = { - let variant_names = variant_names_idents.iter().map(|&(ref name, _, _)| name); - quote! { - const VARIANTS: &'static [&'static str] = &[ #(#variant_names),* ]; - } - }; - - let variant_visitor = Stmts(deserialize_generated_identifier(&variant_names_idents, cattrs, true, None),); - - let non_unit_field = field_i(non_unit_index); - let tag_access = match non_unit_variant.style { - Style::Struct => { - quote!(repr.#non_unit_field.tag) - } - Style::Tuple | Style::Newtype => { - quote!(repr.#non_unit_field.0) - } - _ => unreachable!() - }; - - let mut sub_params = params.clone(); - let variant_arms_from = variants - .iter() - .enumerate() - .filter(|&(_, variant)| !variant.attrs.skip_deserializing()) - .map( - |(i, variant)| { - let variant_name = field_i(i); - sub_params.this = syn::Path::from(variant_name.clone()); - - let this_decl = if is_unit(variant) { - None - } else { - Some(quote!(let this = &mut repr.#variant_name;)) - }; - let block = Stmts(deserialize_externally_tagged_variant_in_place(&sub_params, variant, cattrs)); - quote! { - (__Field::#variant_name, __variant) => { - { - #this_decl - #block; - } - #tag_access = __Tag::#variant_name; - _serde::export::Result::Ok(()) - } - } - }, - ); - - let all_skipped = variants - .iter() - .all(|variant| variant.attrs.skip_deserializing()); - - let match_variant_from = if all_skipped { - // This is an empty enum like `enum Impossible {}` or an enum in which - // all variants have `#[serde(skip_deserializing)]`. - quote! { - // FIXME: Once we drop support for Rust 1.15: - // let _serde::export::Err(__err) = _serde::de::EnumAccess::variant::<__Field>(__data); - // _serde::export::Err(__err) - _serde::export::Result::map( - _serde::de::EnumAccess::variant::<__Field>(__data), - |(__impossible, _)| match __impossible {}) - } - } else { - let unit_field = field_i(unit_index); - - quote! { - unsafe { - let repr = ::std::mem::transmute::<&mut #this #ty_generics, &mut __EnumRepr>(self.place); - #tag_access = __Tag::#unit_field; - match try!(_serde::de::EnumAccess::variant(__data)) { - #(#variant_arms_from)* - } - } - } - }; - - let repr_cases = variants - .iter() - .enumerate() - .filter_map( - |(i, variant)| { - if is_unit(&variant) { - None - } else { - let variant_name = field_i(i); - Some(quote!(#variant_name: #variant_name)) - } - } - ); - - let tag_cases = variants - .iter() - .enumerate() - .map( - |(i, _variant)| { - let variant_name = field_i(i); - - quote!(#variant_name) - } - ); - - - let repr_payloads = variants - .iter() - .enumerate() - .filter_map( - |(i, variant)| { - let variant_name = field_i(i); - match variant.style { - Style::Struct => { - let fields = variant.fields.iter().enumerate().map(|(j, field)| { - let field_name = field_i(j); - let field_ty = field.ty; - quote!(#field_name: #field_ty) - }); - - let payload = quote! { - #[repr(C)] - #[derive(Copy, Clone)] - #[allow(non_camel_case_types)] - struct #variant_name #ty_generics { - tag: __Tag, - #(#fields),* - } - }; - Some(payload) - } - Style::Tuple | Style::Newtype => { - let fields = variant.fields.iter().map(|field| { - let field_ty = field.ty; - quote!(#field_ty) - }); - - let payload = quote! { - #[repr(C)] - #[derive(Copy, Clone)] - #[allow(non_camel_case_types)] - struct #variant_name #ty_generics ( - __Tag, - #(#fields),* - - ); - }; - Some(payload) - } - Style::Unit => None, - } - - } - ); - - let raw_repr = quote! { - #[repr(C)] - #[allow(non_camel_case_types)] - union __EnumRepr #ty_generics { - #(#repr_cases),* - } - - #int_repr - #[derive(Copy, Clone)] - #[allow(non_camel_case_types)] - enum __Tag { - #(#tag_cases),* - } - - #(#repr_payloads)* - }; - - let de_from_impl_generics = de_impl_generics.in_place(); - let de_from_ty_generics = de_ty_generics.in_place(); - let dest_life = place_lifetime(); - - Some(quote_block! { - #variant_visitor - - struct __Visitor #de_from_impl_generics #where_clause { - place: &#dest_life mut #this #ty_generics, - lifetime: _serde::export::PhantomData<&#delife ()>, - } - - impl #de_from_impl_generics _serde::de::Visitor<#delife> for __Visitor #de_from_ty_generics #where_clause { - type Value = (); - - fn expecting(&self, formatter: &mut _serde::export::Formatter) -> _serde::export::fmt::Result { - _serde::export::Formatter::write_str(formatter, #expecting) - } - - fn visit_enum<__A>(self, __data: __A) -> _serde::export::Result - where __A: _serde::de::EnumAccess<#delife> - { - #raw_repr - - #match_variant_from - } - } - - #variants_stmt - - _serde::Deserializer::deserialize_enum(__deserializer, #type_name, VARIANTS, - __Visitor { - place: __place, - lifetime: _serde::export::PhantomData, - }) - }) -} - fn deserialize_internally_tagged_enum( params: &Parameters, variants: &[Variant], @@ -1657,6 +1367,13 @@ fn deserialize_adjacently_tagged_enum( } }; + fn is_unit(variant: &Variant) -> bool { + match variant.style { + Style::Unit => true, + Style::Struct | Style::Tuple | Style::Newtype => false, + } + } + let mut missing_content = quote! { _serde::export::Err(<__A::Error as _serde::de::Error>::missing_field(#content)) }; @@ -1971,46 +1688,6 @@ fn deserialize_externally_tagged_variant( } } -#[cfg(feature = "deserialize_in_place")] -fn deserialize_externally_tagged_variant_in_place( - params: &Parameters, - variant: &Variant, - cattrs: &attr::Container, -) -> Fragment { - if let Some(_path) = variant.attrs.deserialize_with() { - unimplemented!() - /* - let (wrapper, wrapper_ty, unwrap_fn) = - wrap_deserialize_variant_with(params, &variant, path); - return quote_block! { - #wrapper - _serde::export::Result::map( - _serde::de::VariantAccess::newtype_variant::<#wrapper_ty>(__variant), #unwrap_fn) - }; - */ - } - - let variant_ident = &variant.ident; - - match variant.style { - Style::Unit => { - quote_block! { - try!(_serde::de::VariantAccess::unit_variant(__variant)); - } - } - Style::Newtype => { - deserialize_externally_tagged_newtype_variant_in_place(variant_ident, params, &variant.fields[0]) - } - Style::Tuple => { - deserialize_tuple_in_place(Some(variant_ident.clone()), params, &variant.fields, cattrs, None) - } - Style::Struct => { - unimplemented!() - // deserialize_struct(None, params, &variant.fields, cattrs, None, Untagged::No).0 - } - } -} - fn deserialize_internally_tagged_variant( params: &Parameters, variant: &Variant, @@ -2135,34 +1812,6 @@ fn deserialize_externally_tagged_newtype_variant( } } -#[cfg(feature = "deserialize_in_place")] -fn deserialize_externally_tagged_newtype_variant_in_place( - _variant_ident: &syn::Ident, - params: &Parameters, - field: &Field, -) -> Fragment { - let _this = ¶ms.this; - match field.attrs.deserialize_with() { - None => { - quote_expr! { - try!(_serde::de::VariantAccess::newtype_variant_seed(__variant, _serde::private::de::InPlaceSeed(&mut this.1))); - } - } - Some(_path) => { - unimplemented!(); - /* - let (wrapper, wrapper_ty) = wrap_deserialize_field_with(params, field.ty, path); - quote_block! { - #wrapper - _serde::export::Result::map( - _serde::de::VariantAccess::newtype_variant::<#wrapper_ty>(__variant), - |__wrapper| #this::#variant_ident(__wrapper.value)) - } - */ - } - } -} - fn deserialize_untagged_newtype_variant( variant_ident: &syn::Ident, params: &Parameters, @@ -3352,10 +3001,3 @@ fn split_with_de_lifetime( let (_, ty_generics, where_clause) = params.generics.split_for_impl(); (de_impl_generics, de_ty_generics, ty_generics, where_clause) } - -fn is_unit(variant: &Variant) -> bool { - match variant.style { - Style::Unit => true, - Style::Struct | Style::Tuple | Style::Newtype => false, - } -} diff --git a/third_party/rust/serde_derive/src/internals/ast.rs b/third_party/rust/serde_derive/src/internals/ast.rs index 67442f27f2bc..c66b8cff5010 100644 --- a/third_party/rust/serde_derive/src/internals/ast.rs +++ b/third_party/rust/serde_derive/src/internals/ast.rs @@ -25,7 +25,7 @@ pub struct Container<'a> { /// /// Analagous to `syn::Data`. pub enum Data<'a> { - Enum(Repr, Vec>), + Enum(Vec>), Struct(Style, Vec>), } @@ -46,12 +46,6 @@ pub struct Field<'a> { pub original: &'a syn::Field, } -pub struct Repr { - pub int_repr: Option<&'static str>, - pub c_repr: bool, - pub other_repr: bool, -} - #[derive(Copy, Clone)] pub enum Style { /// Named fields. @@ -75,8 +69,7 @@ impl<'a> Container<'a> { let mut data = match item.data { syn::Data::Enum(ref data) => { - let (repr, variants) = enum_from_ast(cx, item, &data.variants, attrs.default()); - Data::Enum(repr, variants) + Data::Enum(enum_from_ast(cx, &data.variants, attrs.default())) } syn::Data::Struct(ref data) => { let (style, fields) = struct_from_ast(cx, &data.fields, None, attrs.default()); @@ -90,7 +83,7 @@ impl<'a> Container<'a> { let mut has_flatten = false; match data { - Data::Enum(_, ref mut variants) => { + Data::Enum(ref mut variants) => { for variant in variants { variant.attrs.rename_by_rules(attrs.rename_all_rules()); for field in &mut variant.fields { @@ -132,7 +125,7 @@ impl<'a> Container<'a> { impl<'a> Data<'a> { pub fn all_fields(&'a self) -> Box> + 'a> { match *self { - Data::Enum(_, ref variants) => { + Data::Enum(ref variants) => { Box::new(variants.iter().flat_map(|variant| variant.fields.iter())) } Data::Struct(_, ref fields) => Box::new(fields.iter()), @@ -144,37 +137,16 @@ impl<'a> Data<'a> { } } -impl Repr { - /// Gives the int type to use for the `repr(int)` enum layout - pub fn get_stable_rust_enum_layout(&self) -> Option<&'static str> { - if self.c_repr || self.other_repr { - None - } else { - self.int_repr - } - } - - /// Gives the int type to use for the `repr(C, int)` enum layout - pub fn get_stable_c_enum_layout(&self) -> Option<&'static str> { - if !self.c_repr && self.other_repr { - None - } else { - self.int_repr - } - } -} - fn enum_from_ast<'a>( cx: &Ctxt, - item: &'a syn::DeriveInput, variants: &'a Punctuated, - container_default: &attr::Default -) -> (Repr, Vec>) { - let variants = variants + container_default: &attr::Default, +) -> Vec> { + variants .iter() .map(|variant| { let attrs = attr::Variant::from_ast(cx, variant); - let (style, fields) = + let (style, fields) = struct_from_ast(cx, &variant.fields, Some(&attrs), container_default); Variant { ident: variant.ident.clone(), @@ -184,48 +156,7 @@ fn enum_from_ast<'a>( original: variant, } }) - .collect(); - - // Compute repr info for enum optimizations - static INT_TYPES: [&'static str; 12] = [ - "u8", "u16", "u32", "u64", "u128", "usize", - "i8", "i16", "i32", "i64", "i128", "isize", - ]; - - let mut int_repr = None; - let mut c_repr = false; - let mut other_repr = false; - - for attr in &item.attrs { - if let Some(syn::Meta::List(ref list)) = attr.interpret_meta() { - if list.ident == "repr" { - // has_repr = true; - for repr in &list.nested { - if let syn::NestedMeta::Meta(syn::Meta::Word(ref repr)) = *repr { - if repr == "C" { - c_repr = true; - } else if let Some(int_type) = INT_TYPES.iter().cloned().find(|int_type| repr == int_type) { - if int_repr.is_some() { - // This shouldn't happen, but we shouldn't crash if we see it. - // So just treat the enum as having a mysterious other repr, - // which makes us discard any attempt to optimize based on layout. - other_repr = true; - } - int_repr = Some(int_type); - } else { - other_repr = true; - } - } else { - panic!("impossible repr? {:?}", repr); - } - } - } - } - } - - let repr = Repr { int_repr, c_repr, other_repr }; - - (repr, variants) + .collect() } fn struct_from_ast<'a>( diff --git a/third_party/rust/serde_derive/src/internals/check.rs b/third_party/rust/serde_derive/src/internals/check.rs index 3fa72412a583..19d8dd874f77 100644 --- a/third_party/rust/serde_derive/src/internals/check.rs +++ b/third_party/rust/serde_derive/src/internals/check.rs @@ -19,7 +19,7 @@ pub fn check(cx: &Ctxt, cont: &mut Container, derive: Derive) { /// attribute. fn check_getter(cx: &Ctxt, cont: &Container) { match cont.data { - Data::Enum(_, _) => { + Data::Enum(_) => { if cont.data.has_getter() { cx.error_spanned_by( cont.original, @@ -42,7 +42,7 @@ fn check_getter(cx: &Ctxt, cont: &Container) { /// Flattening has some restrictions we can test. fn check_flatten(cx: &Ctxt, cont: &Container) { match cont.data { - Data::Enum(_, ref variants) => { + Data::Enum(ref variants) => { for variant in variants { for field in &variant.fields { check_flatten_field(cx, variant.style, field); @@ -86,7 +86,7 @@ fn check_flatten_field(cx: &Ctxt, style: Style, field: &Field) { /// last variant may be a newtype variant which is an implicit "other" case. fn check_identifier(cx: &Ctxt, cont: &Container) { let variants = match cont.data { - Data::Enum(_, ref variants) => variants, + Data::Enum(ref variants) => variants, Data::Struct(_, _) => { return; } @@ -170,7 +170,7 @@ fn check_identifier(cx: &Ctxt, cont: &Container) { /// (de)serialize_with. fn check_variant_skip_attrs(cx: &Ctxt, cont: &Container) { let variants = match cont.data { - Data::Enum(_, ref variants) => variants, + Data::Enum(ref variants) => variants, Data::Struct(_, _) => { return; } @@ -252,7 +252,7 @@ fn check_variant_skip_attrs(cx: &Ctxt, cont: &Container) { /// the to-be-deserialized input. fn check_internal_tag_field_name_conflict(cx: &Ctxt, cont: &Container) { let variants = match cont.data { - Data::Enum(_, ref variants) => variants, + Data::Enum(ref variants) => variants, Data::Struct(_, _) => return, }; @@ -338,7 +338,7 @@ fn check_transparent(cx: &Ctxt, cont: &mut Container, derive: Derive) { } let fields = match cont.data { - Data::Enum(_, _) => { + Data::Enum(_) => { cx.error_spanned_by( cont.original, "#[serde(transparent)] is not allowed on an enum", diff --git a/third_party/rust/serde_derive/src/pretend.rs b/third_party/rust/serde_derive/src/pretend.rs index efe61b5b040c..c4ffe12dab2d 100644 --- a/third_party/rust/serde_derive/src/pretend.rs +++ b/third_party/rust/serde_derive/src/pretend.rs @@ -53,7 +53,7 @@ fn pretend_fields_used(cont: &Container) -> TokenStream { let (_, ty_generics, _) = cont.generics.split_for_impl(); let patterns = match cont.data { - Data::Enum(_, ref variants) => variants + Data::Enum(ref variants) => variants .iter() .filter_map(|variant| match variant.style { Style::Struct => { @@ -94,7 +94,7 @@ fn pretend_fields_used(cont: &Container) -> TokenStream { // fn pretend_variants_used(cont: &Container) -> TokenStream { let variants = match cont.data { - Data::Enum(_, ref variants) => variants, + Data::Enum(ref variants) => variants, Data::Struct(_, _) => { return quote!(); } diff --git a/third_party/rust/serde_derive/src/ser.rs b/third_party/rust/serde_derive/src/ser.rs index 0984b5c8d079..4d1f680dbab7 100644 --- a/third_party/rust/serde_derive/src/ser.rs +++ b/third_party/rust/serde_derive/src/ser.rs @@ -159,7 +159,7 @@ fn serialize_body(cont: &Container, params: &Parameters) -> Fragment { serialize_into(params, type_into) } else { match cont.data { - Data::Enum(_, ref variants) => serialize_enum(params, variants, &cont.attrs), + Data::Enum(ref variants) => serialize_enum(params, variants, &cont.attrs), Data::Struct(Style::Struct, ref fields) => { serialize_struct(params, fields, &cont.attrs) } @@ -177,7 +177,7 @@ fn serialize_body(cont: &Container, params: &Parameters) -> Fragment { fn serialize_transparent(cont: &Container, params: &Parameters) -> Fragment { let fields = match cont.data { Data::Struct(_, ref fields) => fields, - Data::Enum(_, _) => unreachable!(), + Data::Enum(_) => unreachable!(), }; let self_var = ¶ms.self_var; diff --git a/toolkit/components/certviewer/content/.eslintrc.js b/toolkit/components/certviewer/content/.eslintrc.js new file mode 100644 index 000000000000..2f65123f2cee --- /dev/null +++ b/toolkit/components/certviewer/content/.eslintrc.js @@ -0,0 +1,13 @@ +module.exports = { + "parserOptions": { + "sourceType": "module", + }, + "env": { + "node": true + }, + "globals": { + "asn1js": true, + "pvutils": true, + "pkijs": true, + }, +} \ No newline at end of file diff --git a/toolkit/components/certviewer/content/README.md b/toolkit/components/certviewer/content/README.md new file mode 100644 index 000000000000..53f104072b26 --- /dev/null +++ b/toolkit/components/certviewer/content/README.md @@ -0,0 +1,14 @@ +# Certificate Viewer + +## Dependencies + +[PKI.js](https://github.com/PeculiarVentures/PKI.js) +[ASN1.js](https://github.com/PeculiarVentures/ASN1.js) +[pvutils.js](https://github.com/PeculiarVentures/pvutils) +[Browserify](http://browserify.org/) + +## Updating dependencies + +Install all the dependencies doing `npm i`. + +Run `npm run build` any time you add something new to `pvutils.js`, `pkijs.js`, `asn1.js` or any other file required in that one. diff --git a/toolkit/components/certviewer/content/asn1js.js b/toolkit/components/certviewer/content/asn1js.js new file mode 100644 index 000000000000..8ff263532520 --- /dev/null +++ b/toolkit/components/certviewer/content/asn1js.js @@ -0,0 +1,9 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +const asn1js = require("asn1js"); // version 2.0.22 + +module.exports = { + asn1js, +}; diff --git a/toolkit/components/certviewer/content/certDecoder.js b/toolkit/components/certviewer/content/certDecoder.js new file mode 100644 index 000000000000..df2e42b096cc --- /dev/null +++ b/toolkit/components/certviewer/content/certDecoder.js @@ -0,0 +1,555 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +const { fromBER } = asn1js.asn1js; +const { Certificate } = pkijs.pkijs; +import { + b64urltodec, + b64urltohex, + getObjPath, + hash, + hashify, +} from "chrome://global/content/certviewer/utils.js"; +import { strings } from "chrome://global/content/certviewer/strings.js"; +import { ctLogNames } from "chrome://global/content/certviewer/ctlognames.js"; + +const getTimeZone = () => { + let timeZone = new Date().toString().match(/\(([A-Za-z\s].*)\)/); + if (timeZone === null) { + // America/Chicago + timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone; + } else if (timeZone.length > 1) { + timeZone = timeZone[1]; // Central Daylight Time + } else { + timeZone = "Local Time"; // not sure if this is right, but let's go with it for now + } + return timeZone; +}; + +const getPublicKeyInfo = x509 => { + let spki = Object.assign( + { + crv: undefined, + e: undefined, + kty: undefined, + n: undefined, + keysize: undefined, + x: undefined, + xy: undefined, + y: undefined, + }, + x509.subjectPublicKeyInfo + ); + + if (spki.kty === "RSA") { + spki.e = b64urltodec(spki.e); // exponent + spki.keysize = b64urltohex(spki.n).length * 8; // key size in bits + spki.n = hashify(b64urltohex(spki.n)); // modulus + } else if (spki.kty === "EC") { + spki.kty = "Elliptic Curve"; + spki.keysize = parseInt(spki.crv.split("-")[1]); // this is a bit hacky + spki.x = hashify(b64urltohex(spki.x)); // x coordinate + spki.y = hashify(b64urltohex(spki.y)); // y coordinate + spki.xy = `04:${spki.x}:${spki.y}`; // 04 (uncompressed) public key + } + return spki; +}; + +const getX509Ext = (extensions, v) => { + for (var extension in extensions) { + if (extensions[extension].extnID === v) { + return extensions[extension]; + } + } + return { + extnValue: undefined, + parsedValue: undefined, + }; +}; + +const getKeyUsages = (x509, criticalExtensions) => { + let keyUsages = { + critical: criticalExtensions.includes("2.5.29.15"), + purposes: [], + }; + + let keyUsagesBS = getX509Ext(x509.extensions, "2.5.29.15").parsedValue; + if (keyUsagesBS !== undefined) { + // parse the bit string, shifting as necessary + let unusedBits = keyUsagesBS.valueBlock.unusedBits; + keyUsagesBS = parseInt(keyUsagesBS.valueBlock.valueHex, 16) >> unusedBits; + + // iterate through the bit string + strings.keyUsages.slice(unusedBits - 1).forEach(usage => { + if (keyUsagesBS & 1) { + keyUsages.purposes.push(usage); + } + + keyUsagesBS = keyUsagesBS >> 1; + }); + + // reverse the order for legibility + keyUsages.purposes.reverse(); + } + + return keyUsages; +}; + +const parseSubsidiary = distinguishedNames => { + const subsidiary = { + cn: "", + dn: [], + entries: [], + }; + + distinguishedNames.forEach(dn => { + const name = strings.names[dn.type]; + const value = dn.value.valueBlock.value; + + if (name === undefined) { + subsidiary.dn.push(`OID.${dn.type}=${value}`); + subsidiary.entries.push([`OID.${dn.type}`, value]); + } else if (name.short === undefined) { + subsidiary.dn.push(`OID.${dn.type}=${value}`); + subsidiary.entries.push([name.long, value]); + } else { + subsidiary.dn.push(`${name.short}=${value}`); + subsidiary.entries.push([name.long, value]); + + // add the common name for tab display + if (name.short === "cn") { + subsidiary.cn = value; + } + } + }); + + // turn path into a string + subsidiary.dn = subsidiary.dn.join(", "); + + return subsidiary; +}; + +const getSubjectAltNames = (x509, criticalExtensions) => { + let san = getX509Ext(x509.extensions, "2.5.29.17").parsedValue; + if (san && san.hasOwnProperty("altNames")) { + san = Object.keys(san.altNames).map(x => { + const type = san.altNames[x].type; + + switch (type) { + case 4: // directory + return [ + strings.san[type], + parseSubsidiary(san.altNames[x].value.typesAndValues).dn, + ]; + case 7: // ip address + let address = san.altNames[x].value.valueBlock.valueHex; + + if (address.length === 8) { + // ipv4 + return [ + strings.san[type], + address + .match(/.{1,2}/g) + .map(x => parseInt(x, 16)) + .join("."), + ]; + } else if (address.length === 32) { + // ipv6 + return [ + strings.san[type], + address + .toLowerCase() + .match(/.{1,4}/g) + .join(":") + .replace(/\b:?(?:0+:?){2,}/, "::"), + ]; + } + return [strings.san[type], "Unknown IP address"]; + + default: + return [strings.san[type], san.altNames[x].value]; + } + }); + } else { + san = []; + } + san = { + altNames: san, + critical: criticalExtensions.includes("2.5.29.17"), + }; + return san; +}; + +const getBasicConstraints = (x509, criticalExtensions) => { + let basicConstraints; + const basicConstraintsExt = getX509Ext(x509.extensions, "2.5.29.19"); + if (basicConstraintsExt && basicConstraintsExt.parsedValue) { + basicConstraints = { + cA: + basicConstraintsExt.parsedValue.cA !== undefined && + basicConstraintsExt.parsedValue.cA, + critical: criticalExtensions.includes("2.5.29.19"), + }; + } + return basicConstraints; +}; + +const getEKeyUsages = (x509, criticalExtensions) => { + let eKeyUsages = getX509Ext(x509.extensions, "2.5.29.37").parsedValue; + if (eKeyUsages) { + eKeyUsages = { + critical: criticalExtensions.includes("2.5.29.37"), + purposes: eKeyUsages.keyPurposes.map(x => strings.eKU[x] || x), + }; + } + return eKeyUsages; +}; + +const getSubjectKeyID = (x509, criticalExtensions) => { + let sKID = getX509Ext(x509.extensions, "2.5.29.14").parsedValue; + if (sKID) { + sKID = { + critical: criticalExtensions.includes("2.5.29.14"), + id: hashify(sKID.valueBlock.valueHex), + }; + } + return sKID; +}; + +const getAuthorityKeyID = (x509, criticalExtensions) => { + let aKID = getX509Ext(x509.extensions, "2.5.29.35").parsedValue; + if (aKID) { + aKID = { + critical: criticalExtensions.includes("2.5.29.35"), + id: hashify(aKID.keyIdentifier.valueBlock.valueHex), + }; + } + return aKID; +}; + +const getCRLPoints = (x509, criticalExtensions) => { + let crlPoints = getX509Ext(x509.extensions, "2.5.29.31").parsedValue; + if (crlPoints) { + crlPoints = { + critical: criticalExtensions.includes("2.5.29.31"), + points: crlPoints.distributionPoints.map( + x => x.distributionPoint[0].value + ), + }; + } + return crlPoints; +}; + +const getOcspStaple = (x509, criticalExtensions) => { + let ocspStaple = getX509Ext(x509.extensions, "1.3.6.1.5.5.7.1.24").extnValue; + if (ocspStaple && ocspStaple.valueBlock.valueHex === "3003020105") { + ocspStaple = { + critical: criticalExtensions.includes("1.3.6.1.5.5.7.1.24"), + required: true, + }; + } else { + ocspStaple = { + critical: criticalExtensions.includes("1.3.6.1.5.5.7.1.24"), + required: false, + }; + } + return ocspStaple; +}; + +const getAuthorityInfoAccess = (x509, criticalExtensions) => { + let aia = getX509Ext(x509.extensions, "1.3.6.1.5.5.7.1.1").parsedValue; + if (aia) { + aia = aia.accessDescriptions.map(x => { + return { + location: x.accessLocation.value, + method: strings.aia[x.accessMethod], + }; + }); + } + + aia = { + descriptions: aia, + critical: criticalExtensions.includes("1.3.6.1.5.5.7.1.1"), + }; + return aia; +}; + +const getSCTs = (x509, criticalExtensions) => { + let scts = getX509Ext(x509.extensions, "1.3.6.1.4.1.11129.2.4.2").parsedValue; + if (scts) { + scts = Object.keys(scts.timestamps).map(x => { + let logId = scts.timestamps[x].logID.toLowerCase(); + return { + logId: hashify(logId), + name: ctLogNames.hasOwnProperty(logId) ? ctLogNames[logId] : undefined, + signatureAlgorithm: `${scts.timestamps[x].hashAlgorithm.replace( + "sha", + "SHA-" + )} ${scts.timestamps[x].signatureAlgorithm.toUpperCase()}`, + timestamp: `${scts.timestamps[ + x + ].timestamp.toLocaleString()} (${getTimeZone()})`, + version: scts.timestamps[x].version + 1, + }; + }); + } else { + scts = []; + } + + scts = { + critical: criticalExtensions.includes("1.3.6.1.4.1.11129.2.4.2"), + timestamps: scts, + }; + return scts; +}; + +const getCertificatePolicies = (x509, criticalExtensions) => { + let cp = getX509Ext(x509.extensions, "2.5.29.32").parsedValue; + if (cp && cp.hasOwnProperty("certificatePolicies")) { + cp = cp.certificatePolicies.map(x => { + let id = x.policyIdentifier; + let name = strings.cps.hasOwnProperty(id) + ? strings.cps[id].name + : undefined; + let qualifiers = undefined; + let value = strings.cps.hasOwnProperty(id) + ? strings.cps[id].value + : undefined; + + // ansi organization identifiers + if (id.startsWith("2.16.840.")) { + value = id; + id = "2.16.840"; + name = strings.cps["2.16.840"].name; + } + + // statement identifiers + if (id.startsWith("1.3.6.1.4.1")) { + value = id; + id = "1.3.6.1.4.1"; + name = strings.cps["1.3.6.1.4.1"].name; + } + + if (x.hasOwnProperty("policyQualifiers")) { + qualifiers = x.policyQualifiers.map(qualifier => { + let id = qualifier.policyQualifierId; + let name = strings.cps.hasOwnProperty(id) + ? strings.cps[id].name + : undefined; + let value = qualifier.qualifier.valueBlock.value; + + // sometimes they are multiple qualifier subblocks, and for now we'll + // only return the first one because it's getting really messy at this point + if (Array.isArray(value) && value.length === 1) { + value = value[0].valueBlock.value; + } else if (Array.isArray(value) && value.length > 1) { + value = "(currently unsupported)"; + } + + return { + id, + name, + value, + }; + }); + } + + return { + id, + name, + qualifiers, + value, + }; + }); + } + + cp = { + critical: criticalExtensions.includes("2.5.29.32"), + policies: cp, + }; + return cp; +}; + +const getMicrosoftCryptographicExtensions = (x509, criticalExtensions) => { + // now let's parse the Microsoft cryptographic extensions + let msCrypto = { + caVersion: getX509Ext(x509.extensions, "1.3.6.1.4.1.311.21.1").parsedValue, + certificatePolicies: getX509Ext(x509.extensions, "1.3.6.1.4.1.311.21.10") + .parsedValue, + certificateTemplate: getX509Ext(x509.extensions, "1.3.6.1.4.1.311.21.7") + .parsedValue, + certificateType: getX509Ext(x509.extensions, "1.3.6.1.4.1.311.20.2") + .parsedValue, + previousHash: getX509Ext(x509.extensions, "1.3.6.1.4.1.311.21.2") + .parsedValue, + }; + + if ( + msCrypto.caVersion && + Number.isInteger(msCrypto.caVersion.keyIndex) && + Number.isInteger(msCrypto.caVersion.certificateIndex) + ) { + msCrypto.caVersion = { + critical: criticalExtensions.includes("1.3.6.1.4.1.311.21.1"), + caRenewals: msCrypto.caVersion.certificateIndex, + keyReuses: + msCrypto.caVersion.certificateIndex - msCrypto.caVersion.keyIndex, + }; + } + + if (msCrypto.certificatePolicies) { + msCrypto.certificatePolicies = { + critical: criticalExtensions.includes("1.3.6.1.4.1.311.21.10"), + purposes: msCrypto.certificatePolicies.certificatePolicies.map( + x => strings.eKU[x.policyIdentifier] || x.policyIdentifier + ), + }; + } + + if (msCrypto.certificateTemplate) { + msCrypto.certificateTemplate = { + critical: criticalExtensions.includes("1.3.6.1.4.1.311.21.7"), + id: msCrypto.certificateTemplate.extnID, + major: msCrypto.certificateTemplate.templateMajorVersion, + minor: msCrypto.certificateTemplate.templateMinorVersion, + }; + } + + if (msCrypto.certificateType) { + msCrypto.certificateType = { + critical: criticalExtensions.includes("1.3.6.1.4.1.311.20.2"), + type: + strings.microsoftCertificateTypes[ + msCrypto.certificateType.valueBlock.value + ] || "Unknown", + }; + } + + if (msCrypto.previousHash) { + msCrypto.previousHash = { + critical: criticalExtensions.includes("1.3.6.1.4.1.311.21.2"), + previousHash: hashify(msCrypto.previousHash.valueBlock.valueHex), + }; + } + + msCrypto.exists = !!( + msCrypto.caVersion || + msCrypto.certificatePolicies || + msCrypto.certificateTemplate || + msCrypto.certificateType || + msCrypto.previousHash + ); + + return msCrypto; +}; + +export const parse = async certificate => { + // certificate could be an array of BER or an array of buffers + const supportedExtensions = [ + "1.3.6.1.4.1.311.20.2", // microsoft certificate type + "1.3.6.1.4.1.311.21.2", // microsoft certificate previous hash + "1.3.6.1.4.1.311.21.7", // microsoft certificate template + "1.3.6.1.4.1.311.21.1", // microsoft certification authority renewal + "1.3.6.1.4.1.311.21.10", // microsoft certificate policies + "1.3.6.1.4.1.11129.2.4.2", // embedded scts + "1.3.6.1.5.5.7.1.1", // authority info access + "1.3.6.1.5.5.7.1.24", // ocsp stapling + "1.3.101.77", // ct redaction - deprecated and not displayed + "2.5.29.14", // subject key identifier + "2.5.29.15", // key usages + "2.5.29.17", // subject alt names + "2.5.29.19", // basic constraints + "2.5.29.31", // crl points + "2.5.29.32", // certificate policies + "2.5.29.35", // authority key identifier + "2.5.29.37", // extended key usage + ]; + + let timeZone = getTimeZone(); + + // parse the certificate + const asn1 = fromBER(certificate); + + let x509 = new Certificate({ schema: asn1.result }); + x509 = x509.toJSON(); + + // convert the cert to PEM + const certBTOA = window + .btoa(String.fromCharCode.apply(null, new Uint8Array(certificate))) + .match(/.{1,64}/g) + .join("\r\n"); + + // get which extensions are critical + const criticalExtensions = []; + x509.extensions.forEach(ext => { + if (ext.hasOwnProperty("critical") && ext.critical === true) { + criticalExtensions.push(ext.extnID); + } + }); + + const spki = getPublicKeyInfo(x509); + const keyUsages = getKeyUsages(x509, criticalExtensions); + const san = getSubjectAltNames(x509, criticalExtensions); + const basicConstraints = getBasicConstraints(x509, criticalExtensions); + const eKeyUsages = getEKeyUsages(x509, criticalExtensions); + const sKID = getSubjectKeyID(x509, criticalExtensions); + const aKID = getAuthorityKeyID(x509, criticalExtensions); + const crlPoints = getCRLPoints(x509, criticalExtensions); + const ocspStaple = getOcspStaple(x509, criticalExtensions); + const aia = getAuthorityInfoAccess(x509, criticalExtensions); + const scts = getSCTs(x509, criticalExtensions); + const cp = getCertificatePolicies(x509, criticalExtensions); + const msCrypto = getMicrosoftCryptographicExtensions( + x509, + criticalExtensions + ); + + // determine which extensions weren't supported + let unsupportedExtensions = []; + x509.extensions.forEach(ext => { + if (!supportedExtensions.includes(ext.extnID)) { + unsupportedExtensions.push(ext.extnID); + } + }); + + // the output shell + return { + ext: { + aia, + aKID, + basicConstraints, + crlPoints, + cp, + eKeyUsages, + keyUsages, + msCrypto, + ocspStaple, + scts, + sKID, + san, + }, + files: { + der: undefined, // TODO: implement! + pem: encodeURI( + `-----BEGIN CERTIFICATE-----\r\n${certBTOA}\r\n-----END CERTIFICATE-----\r\n` + ), + }, + fingerprint: { + sha1: await hash("SHA-1", certificate), + sha256: await hash("SHA-256", certificate), + }, + issuer: parseSubsidiary(x509.issuer.typesAndValues), + notBefore: `${x509.notBefore.value.toLocaleString()} (${timeZone})`, + notAfter: `${x509.notAfter.value.toLocaleString()} (${timeZone})`, + subject: parseSubsidiary(x509.subject.typesAndValues), + serialNumber: hashify(getObjPath(x509, "serialNumber.valueBlock.valueHex")), + signature: { + name: strings.signature[getObjPath(x509, "signature.algorithmId")], + type: getObjPath(x509, "signature.algorithmId"), + }, + subjectPublicKeyInfo: spki, + unsupportedExtensions, + version: (x509.version + 1).toString(), + }; +}; diff --git a/toolkit/components/certviewer/content/certviewer.html b/toolkit/components/certviewer/content/certviewer.html index b0d51cffc466..9602b14cf3c5 100644 --- a/toolkit/components/certviewer/content/certviewer.html +++ b/toolkit/components/certviewer/content/certviewer.html @@ -10,11 +10,14 @@ - + + + + - - + + about:certificate diff --git a/toolkit/components/certviewer/content/certviewer.js b/toolkit/components/certviewer/content/certviewer.js index b1c4145acd52..0db4ef72caf4 100644 --- a/toolkit/components/certviewer/content/certviewer.js +++ b/toolkit/components/certviewer/content/certviewer.js @@ -6,13 +6,20 @@ "use strict"; +import { parse } from "chrome://global/content/certviewer/certDecoder.js"; +const { stringToArrayBuffer } = pvutils.pvutils; + +const derString = + '0\x82\x06F0\x82\x05.\xA0\x03\x02\x01\x02\x02\x10\f\x97n>B8\xF4 \xD6=\xDF\x86\xEF\xEB\xBA\x900\r\x06\t*\x86H\x86\xF7\r\x01\x01\v\x05\x000M1\v0\t\x06\x03U\x04\x06\x13\x02US1\x150\x13\x06\x03U\x04\n\x13\fDigiCert Inc1\'0%\x06\x03U\x04\x03\x13\x1EDigiCert SHA2 Secure Server CA0\x1E\x17\r181105000000Z\x17\r191113120000Z0\x81\x831\v0\t\x06\x03U\x04\x06\x13\x02US1\x130\x11\x06\x03U\x04\b\x13\nCalifornia1\x160\x14\x06\x03U\x04\x07\x13\rMountain View1\x1C0\x1A\x06\x03U\x04\n\x13\x13Mozilla Corporation1\x0F0\r\x06\x03U\x04\v\x13\x06WebOps1\x180\x16\x06\x03U\x04\x03\x13\x0Fwww.mozilla.org0\x82\x01"0\r\x06\t*\x86H\x86\xF7\r\x01\x01\x01\x05\x00\x03\x82\x01\x0F\x000\x82\x01\n\x02\x82\x01\x01\x00\xB8\xAA\xEE\xCAi$\x9AJ\x82&\x1E\xD0\x8Ee\xE5P\xE0\\,Tr\xC3\x92\xC6\xFE\xF5\x14YZ\xEC\xC4-\xA0\xB1\xB4|X\x9A\xBEq\x8A\x18\x06\x9A\rU+J\xAC\xEE\x14\xDA\xB0a\xD4a\x1Bq\xCB\xD3\xEA\xA2\x8E@\x8F\xA9\x8E0\xF1\xC7\xD7&E\xDB\x9B\x191\xA9\xF0\xBD\f\x17Z!V\xF8H\xBD\x82\xEE\x98\xE1(D0\xCFS\x83\xEF\x18\x98\xC6\x85\xE9?\xA2;\xDEt\xF5\x9E\xF1\xD8\\\x88y18-\xAA^\vU?fr \xFEUn\x9B\x1DD\x97\x0F\xDCb|\xBFC\xA9\xD2t!\xCD\x12\x96T\xE53\xEA*\xE5\xA0\x1E;\x15\x10\x19xW"\xA8\xFA}$/\xF5\xF4\r\xEAe\xF1@\x8A\x1C\xFE\b\xF1\xB5\xEB$\xAB\xF5e\xF1\x89\x98\xD4R\x19?\xD0a\xEE\r\xBB\x93\x16}\x18\x00\x06B\xD8\xD3/M\xD1\xCC\xA0.J\x0E\xB2x\x89\x98U\xD4\x16j\xC7;P\xF9\xC1^T@\xCD\x9F>8\x94\xE1Q\xBC\xCA\xD7\xA6\xB6\b\x8D\xD1\x83\x86\xA0)"d\xFA\xE08\xEE\x1D\x7F"i\xA7\x82\x91KE\xBF\xCC\xBD\x15\xFA\x1FZ\x16qK\xB2\x1F\xA3\xBB=\x97e\xD1\x8ApN\x9C5Lr.\xA8!\xA5\xFF\nO\x83$ q3'; + let gElements = {}; document.addEventListener("DOMContentLoaded", e => { + buildChain(); gElements.certificateSection = document.querySelector("certificate-section"); }); -const updateSelectedItem = (() => { +export const updateSelectedItem = (() => { let state; return selectedItem => { if (selectedItem) { @@ -25,3 +32,12 @@ const updateSelectedItem = (() => { return state; }; })(); + +const buildChain = async () => { + let chain = [derString]; + let builtChain = chain.map(cert => { + return stringToArrayBuffer(cert); + }); + let certs = await Promise.all(builtChain.map(cert => parse(cert))); + console.log("certs ", certs); +}; diff --git a/toolkit/components/certviewer/content/components/certificate-section.js b/toolkit/components/certviewer/content/components/certificate-section.js index 8acf27b5f2d1..07a1e64b10f4 100644 --- a/toolkit/components/certviewer/content/components/certificate-section.js +++ b/toolkit/components/certviewer/content/components/certificate-section.js @@ -2,7 +2,10 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -/* globals certArray, updateSelectedItem, InfoGroup, ErrorSection */ +/* globals InfoGroup, ErrorSection */ + +import { updateSelectedItem } from "chrome://global/content/certviewer/certviewer.js"; +import { certArray } from "chrome://global/content/certviewer/components/dummy-info.js"; class CertificateSection extends HTMLElement { constructor() { diff --git a/toolkit/components/certviewer/content/components/dummy-info.js b/toolkit/components/certviewer/content/components/dummy-info.js index bbe36c2c4e49..bb5431a17f81 100644 --- a/toolkit/components/certviewer/content/components/dummy-info.js +++ b/toolkit/components/certviewer/content/components/dummy-info.js @@ -2,26 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -const handshakeArray = [ - { - label: "Protocol", - info: "TLS 1.2", - }, - { - label: "Cipher Suite", - info: "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", - }, - { - label: "Key Exchange Group", - info: "P256", - }, - { - label: "Signature Scheme", - info: "RSA-PKCS1-SHA512", - }, -]; - -const certArray = [ +export const certArray = [ [ { sectionTitle: "Subject Name", diff --git a/toolkit/components/certviewer/content/ctlognames.js b/toolkit/components/certviewer/content/ctlognames.js new file mode 100644 index 000000000000..51b8718cc9f7 --- /dev/null +++ b/toolkit/components/certviewer/content/ctlognames.js @@ -0,0 +1,150 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +export const ctLogNames = { + "9606c02c690033aa1d145f59c6e2648d0549f0df96aab8db915a70d8ecf390a5": + "Akamai CT", + "39376f545f7b4607f59742d768cd5d2437bf3473b6534a4834bcf72e681c83c9": + "Alpha CT", + a577ac9ced7548dd8f025b67a241089df86e0f476ec203c2ecbedb185f282638: "CNNIC CT", + cdb5179b7fc1c046feea31136a3f8f002e6182faf8896fecc8b2f5b5ab604900: "Certly.IO", + "1fbc36e002ede97f40199e86b3573b8a4217d80187746ad0da03a06054d20df4": + "Cloudflare “Nimbus2017”", + db74afeecb29ecb1feca3e716d2ce5b9aabb36f7847183c75d9d4f37b61fbf64: + "Cloudflare “Nimbus2018”", + "747eda8331ad331091219cce254f4270c2bffd5e422008c6373579e6107bcc56": + "Cloudflare “Nimbus2019”", + "5ea773f9df56c0e7b536487dd049e0327a919a0c84a112128418759681714558": + "Cloudflare “Nimbus2020”", + "4494652eb0eeceafc44007d8a8fe28c0dae682bed8cb31b53fd33396b5b681a8": + "Cloudflare “Nimbus2021”", + "41c8cab1df22464a10c6a13a0942875e4e318b1b03ebeb4bc768f090629606f6": + "Cloudflare “Nimbus2022”", + "7a328c54d8b72db620ea38e0521ee98416703213854d3bd22bc13a57a352eb52": + "Cloudflare “Nimbus2023”", + "6ff141b5647e4222f7ef052cefae7c21fd608e27d2af5a6e9f4b8a37d6633ee5": + "DigiCert Nessie2018", + fe446108b1d01ab78a62ccfeab6ab2b2babff3abdad80a4d8b30df2d0008830c: + "DigiCert Nessie2019", + c652a0ec48ceb3fcab170992c43a87413309e80065a26252401ba3362a17c565: + "DigiCert Nessie2020", + eec095ee8d72640f92e3c3b91bc712a3696a097b4b6a1a1438e647b2cbedc5f9: + "DigiCert Nessie2021", + "51a3b0f5fd01799c566db837788f0ca47acc1b27cbf79e88429a0dfed48b05e5": + "DigiCert Nessie2022", + b3737707e18450f86386d605a9dc11094a792db1670c0b87dcf0030e7936a59a: + "DigiCert Nessie2023", + "5614069a2fd7c2ecd3f5e1bd44b23ec74676b9bc99115cc0ef949855d689d0dd": + "DigiCert Server", + "8775bfe7597cf88c43995fbdf36eff568d475636ff4ab560c1b4eaff5ea0830f": + "DigiCert Server 2", + c1164ae0a772d2d4392dc80ac10770d4f0c49bde991a4840c1fa075164f63360: + "DigiCert Yeti2018", + e2694bae26e8e94009e8861bb63b83d43ee7fe7488fba48f2893019dddf1dbfe: + "DigiCert Yeti2019", + f095a459f200d18240102d2f93888ead4bfe1d47e399e1d034a6b0a8aa8eb273: + "DigiCert Yeti2020", + "5cdc4392fee6ab4544b15e9ad456e61037fbd5fa47dca17394b25ee6f6c70eca": + "DigiCert Yeti2021", + "2245450759552456963fa12ff1f76d86e0232663adc04b7f5dc6835c6ee20f02": + "DigiCert Yeti2022", + "35cf191bbfb16c57bf0fad4c6d42cbbbb627202651ea3fe12aefa803c33bd64c": + "DigiCert Yeti2023", + "717ea7420975be84a2723553f1777c26dd51af4e102144094d9019b462fb6668": "GDCA 1", + "14308d90ccd030135005c01ca526d81e84e87624e39b6248e08f724aea3bb42a": "GDCA 2", + c9cf890a21109c666cc17a3ed065c930d0e0135a9feba85af14210b8072421aa: + "GDCA CT #1", + "924a30f909336ff435d6993a10ac75a2c641728e7fc2d659ae6188ffad40ce01": + "GDCA CT #2", + fad4c97cc49ee2f8ac85c5ea5cea09d0220dbbf4e49c6b50662ff868f86b8c28: + "Google “Argon2017”", + a4501269055a15545e6211ab37bc103f62ae5576a45e4b1714453e1b22106a25: + "Google “Argon2018”", + "63f2dbcde83bcc2ccf0b728427576b33a48d61778fbd75a638b1c768544bd88d": + "Google “Argon2019”", + b21e05cc8ba2cd8a204e8766f92bb98a2520676bdafa70e7b249532def8b905e: + "Google “Argon2020”", + f65c942fd1773022145418083094568ee34d131933bfdf0c2f200bcc4ef164e3: + "Google “Argon2021”", + "2979bef09e393921f056739f63a577e5be577d9c600af8f94d5d265c255dc784": + "Google “Argon2022”", + "68f698f81f6482be3a8ceeb9281d4cfc71515d6793d444d10a67acbb4f4ffbc4": + "Google “Aviator”", + c3bf03a7e1ca8841c607bae3ff4270fca5ec45b186ebbe4e2cf3fc778630f5f6: + "Google “Crucible”", + "1d024b8eb1498b344dfd87ea3efc0996f7506f235d1d497061a4773c439c25fb": + "Google “Daedalus”", + "293c519654c83965baaa50fc5807d4b76fbf587a2972dca4c30cf4e54547f478": + "Google “Icarus”", + a4b90990b418581487bb13a2cc67700a3c359804f91bdfb8e377cd0ec80ddc10: + "Google “Pilot”", + ee4bbdb775ce60bae142691fabe19e66a30f7e5fb072d88300c47b897aa8fdcb: + "Google “Rocketeer”", + bbd9dfbc1f8a71b593942397aa927b473857950aab52e81a909664368e1ed185: + "Google “Skydiver”", + "52eb4b225ec896974850675f23e43bc1d021e3214ce52ecd5fa87c203cdfca03": + "Google “Solera2018”", + "0b760e9a8b9a682f88985b15e947501a56446bba8830785c3842994386450c00": + "Google “Solera2019”", + "1fc72ce5a1b799f400c359bff96ca3913548e8644220610952e9ba1774f7bac7": + "Google “Solera2020”", + a3c99845e80ab7ce00157b3742df0207dd272b2b602ecf98ee2c12db9c5ae7e7: + "Google “Solera2021”", + "697aafca1a6b536fae21205046debad7e0eaea13d2432e6e9d8fb379f2b9aaf3": + "Google “Solera2022”", + a899d8780c9290aaf462f31880ccfbd52451e970d0fbf591ef75b0d99b645681: + "Google “Submariner”", + b0cc83e5a5f97d6baf7c09cc284904872ac7e88b132c6350b7c6fd26e16c6c77: + "Google “Testtube”", + b10cd559a6d67846811f7df9a51532739ac48d703bea0323da5d38755bc0ad4e: + "Google “Xenon2018”", + "084114980071532c16190460bcfc47fdc2653afa292c72b37ff863ae29ccc9f0": + "Google “Xenon2019”", + "07b75c1be57d68fff1b0c61d2315c7bae6577c5794b76aeebc613a1a69d3a21c": + "Google “Xenon2020”", + "7d3ef2f88fff88556824c2c0ca9e5289792bc50e78097f2e6a9768997e22f0d7": + "Google “Xenon2021”", + "46a555eb75fa912030b5a28969f4f37d112c4174befd49b885abf2fc70fe6d47": + "Google “Xenon2022”", + "7461b4a09cfb3d41d75159575b2e7649a445a8d27709b0cc564a6482b7eb41a3": "Izenpe", + "8941449c70742e06b9fc9ce7b116ba0024aa36d59af44f0204404f00f7ea8566": + "Izenpe “Argi”", + "296afa2d568bca0d2ea844956ae9721fc35fa355ecda99693aafd458a71aefdd": + "Let“s Encrypt ”Clicky”", + "537b69a3564335a9c04904e39593b2c298eb8d7a6e83023635c627248cd6b440": + "Nordu “flimsy”", + aae70b7f3cb8d566c86c2f16979c9f445f69ab0eb4535589b2f77a030104f3cd: + "Nordu “plausible”", + e0127629e90496564e3d0147984498aa48f8adb16600eb7902a1ef9909906273: + "PuChuangSiDa CT", + cf55e28923497c340d5206d05353aeb25834b52f1f8dc9526809f212efdd7ca6: + "SHECA CT 1", + "32dc59c2d4c41968d56e14bc61ac8f0e45db39faf3c155aa4252f5001fa0c623": + "SHECA CT 2", + db76fdadac65e7d09508886e2159bd8b90352f5fead3e3dc5e22eb350acc7b98: + "Sectigo (Comodo) “Dodo” CT", + "6f5376ac31f03119d89900a45115ff77151c11d902c10029068db2089a37d913": + "Sectigo (Comodo) “Mammoth” CT", + "5581d4c2169036014aea0b9b573c53f0c0e43878702508172fa3aa1d0713d30c": + "Sectigo (Comodo) “Sabre” CT", + "34bb6ad6c3df9c03eea8a499ff7891486c9d5e5cac92d01f7bfd1bce19db48ef": + "StartCom", + ddeb1d2b7a0d4fa6208b81ad8168707e2e8e9d01d55c888d3d11c4cdb6ecbecc: "Symantec", + a7ce4a4e6207e0addee5fdaa4b1f86768767b5d002a55d47310e7e670a95eab2: + "Symantec Deneb", + "15970488d7b997a05beb52512adee8d2e8b4a3165264121a9fabfbd5f85ad93f": + "Symantec “Sirius”", + bc78e1dfc5f63c684649334da10fa15f0979692009c081b4f3f6917f3ed9b8a5: + "Symantec “Vega”", + b0b784bc81c0ddc47544e883f05985bb9077d134d8ab88b2b2e533980b8e508b: + "Up In The Air “Behind the Sofa”", + ac3b9aed7fa9674757159e6d7d575672f9d98100941e9bdeffeca1313b75782d: "Venafi", + "03019df3fd85a69a8ebd1facc6da9ba73e469774fe77f579fc5a08b8328c1d6b": + "Venafi Gen2 CT", + "41b2dc2e89e63ce4af1ba7bb29bf68c6dee6f9f1cc047e30dffae3b3ba259263": "WoSign", + "63d0006026dde10bb0601f452446965ee2b6ea2cd4fbc95ac866a550af9075b7": + "WoSign 2", + "9e4ff73dc3ce220b69217c899e468076abf8d78636d5ccfc85a31a75628ba88b": + "WoSign CT #1", +}; diff --git a/toolkit/components/certviewer/content/package.json b/toolkit/components/certviewer/content/package.json new file mode 100644 index 000000000000..458cd3e27c5f --- /dev/null +++ b/toolkit/components/certviewer/content/package.json @@ -0,0 +1,20 @@ +{ + "name": "certviewer", + "version": "1.0.0", + "description": "", + "scripts": { + "build-pvutils": "./node_modules/browserify/bin/cmd.js pvutils.js --standalone pvutils -o ./vendor/pvutils_bundle.js", + "build-asn1js": "./node_modules/browserify/bin/cmd.js asn1js.js --standalone asn1js -o ./vendor/asn1js_bundle.js", + "build-pkijs": "./node_modules/browserify/bin/cmd.js pkijs.js --standalone pkijs -o ./vendor/pkijs_bundle.js", + "build": "npm run build-pvutils && npm run build-asn1js && npm run build-pkijs" + }, + "license": "MPL-2.0", + "dependencies": { + "asn1js": "^2.0.22", + "pkijs": "^2.1.78", + "pvutils": "^1.0.17" + }, + "devDependencies": { + "browserify": "^16.2.3" + } +} diff --git a/toolkit/components/certviewer/content/pkijs.js b/toolkit/components/certviewer/content/pkijs.js new file mode 100644 index 000000000000..31b877543b69 --- /dev/null +++ b/toolkit/components/certviewer/content/pkijs.js @@ -0,0 +1,9 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +const pkijs = require("pkijs"); // version 2.1.78 + +module.exports = { + pkijs, +}; diff --git a/toolkit/components/certviewer/content/pvutils.js b/toolkit/components/certviewer/content/pvutils.js new file mode 100644 index 000000000000..550c8a11a29c --- /dev/null +++ b/toolkit/components/certviewer/content/pvutils.js @@ -0,0 +1,9 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +const pvutils = require("pvutils"); // version 1.0.17 + +module.exports = { + pvutils, +}; diff --git a/toolkit/components/certviewer/content/strings.js b/toolkit/components/certviewer/content/strings.js new file mode 100644 index 000000000000..4205ed9158a4 --- /dev/null +++ b/toolkit/components/certviewer/content/strings.js @@ -0,0 +1,504 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +export const strings = { + ux: { + upload: "Upload Certificate", + }, + + names: { + // Directory Pilot Attributes + "0.9.2342.19200300.100.1.1": { + short: "uid", + long: "User ID", + }, + "0.9.2342.19200300.100.1.25": { + short: "dc", + long: "Domain Component", + }, + + // PKCS-9 + "1.2.840.113549.1.9.1": { + short: "e", + long: "Email Address", + }, + + // Incorporated Locations + "1.3.6.1.4.1.311.60.2.1.1": { + short: undefined, + long: "Inc. Locality", + }, + "1.3.6.1.4.1.311.60.2.1.2": { + short: undefined, + long: "Inc. State / Province", + }, + "1.3.6.1.4.1.311.60.2.1.3": { + short: undefined, + long: "Inc. Country", + }, + + // microsoft cryptographic extensions + "1.3.6.1.4.1.311.21.7": { + name: { + short: "Certificate Template", + long: "Microsoft Certificate Template", + }, + }, + "1.3.6.1.4.1.311.21.10": { + name: { + short: "Certificate Policies", + long: "Microsoft Certificate Policies", + }, + }, + + // certificate extensions + "1.3.6.1.4.1.11129.2.4.2": { + name: { + short: "Embedded SCTs", + long: "Embedded Signed Certificate Timestamps", + }, + }, + "1.3.6.1.5.5.7.1.1": { + name: { + short: undefined, + long: "Authority Information Access", + }, + }, + "1.3.6.1.5.5.7.1.24": { + name: { + short: "OCSP Stapling", + long: "Online Certificate Status Protocol Stapling", + }, + }, + + // X.500 attribute types + "2.5.4.1": { + short: undefined, + long: "Aliased Entry", + }, + "2.5.4.2": { + short: undefined, + long: "Knowledge Information", + }, + "2.5.4.3": { + short: "cn", + long: "Common Name", + }, + "2.5.4.4": { + short: "sn", + long: "Surname", + }, + "2.5.4.5": { + short: "serialNumber", + long: "Serial Number", + }, + "2.5.4.6": { + short: "c", + long: "Country", + }, + "2.5.4.7": { + short: "l", + long: "Locality", + }, + "2.5.4.8": { + short: "s", + long: "State / Province", + }, + "2.5.4.9": { + short: "street", + long: "Stress Address", + }, + "2.5.4.10": { + short: "o", + long: "Organization", + }, + "2.5.4.11": { + short: "ou", + long: "Organizational Unit", + }, + "2.5.4.12": { + short: "t", + long: "Title", + }, + "2.5.4.13": { + short: "description", + long: "Description", + }, + "2.5.4.14": { + short: undefined, + long: "Search Guide", + }, + "2.5.4.15": { + short: undefined, + long: "Business Category", + }, + "2.5.4.16": { + short: undefined, + long: "Postal Address", + }, + "2.5.4.17": { + short: "postalCode", + long: "Postal Code", + }, + "2.5.4.18": { + short: "POBox", + long: "PO Box", + }, + "2.5.4.19": { + short: undefined, + long: "Physical Delivery Office Name", + }, + "2.5.4.20": { + short: "phone", + long: "Phone Number", + }, + "2.5.4.21": { + short: undefined, + long: "Telex Number", + }, + "2.5.4.22": { + short: undefined, + long: "Teletex Terminal Identifier", + }, + "2.5.4.23": { + short: undefined, + long: "Fax Number", + }, + "2.5.4.24": { + short: undefined, + long: "X.121 Address", + }, + "2.5.4.25": { + short: undefined, + long: "International ISDN Number", + }, + "2.5.4.26": { + short: undefined, + long: "Registered Address", + }, + "2.5.4.27": { + short: undefined, + long: "Destination Indicator", + }, + "2.5.4.28": { + short: undefined, + long: "Preferred Delivery Method", + }, + "2.5.4.29": { + short: undefined, + long: "Presentation Address", + }, + "2.5.4.30": { + short: undefined, + long: "Supported Application Context", + }, + "2.5.4.31": { + short: undefined, + long: "Member", + }, + "2.5.4.32": { + short: undefined, + long: "Owner", + }, + "2.5.4.33": { + short: undefined, + long: "Role Occupant", + }, + "2.5.4.34": { + short: undefined, + long: "See Also", + }, + "2.5.4.35": { + short: undefined, + long: "User Password", + }, + "2.5.4.36": { + short: undefined, + long: "User Certificate", + }, + "2.5.4.37": { + short: undefined, + long: "CA Certificate", + }, + "2.5.4.38": { + short: undefined, + long: "Authority Revocation List", + }, + "2.5.4.39": { + short: undefined, + long: "Certificate Revocation List", + }, + "2.5.4.40": { + short: undefined, + long: "Cross-certificate Pair", + }, + "2.5.4.41": { + short: undefined, + long: "Name", + }, + "2.5.4.42": { + short: "g", + long: "Given Name", + }, + "2.5.4.43": { + short: "i", + long: "Initials", + }, + "2.5.4.44": { + short: undefined, + long: "Generation Qualifier", + }, + "2.5.4.45": { + short: undefined, + long: "Unique Identifier", + }, + "2.5.4.46": { + short: undefined, + long: "DN Qualifier", + }, + "2.5.4.47": { + short: undefined, + long: "Enhanced Search Guide", + }, + "2.5.4.48": { + short: undefined, + long: "Protocol Information", + }, + "2.5.4.49": { + short: "dn", + long: "Distinguished Name", + }, + "2.5.4.50": { + short: undefined, + long: "Unique Member", + }, + "2.5.4.51": { + short: undefined, + long: "House Identifier", + }, + "2.5.4.52": { + short: undefined, + long: "Supported Algorithms", + }, + "2.5.4.53": { + short: undefined, + long: "Delta Revocation List", + }, + "2.5.4.58": { + short: undefined, + long: "Attribute Certificate Attribute", // huh + }, + "2.5.4.65": { + short: undefined, + long: "Pseudonym", + }, + + // extensions + "2.5.29.14": { + name: { + short: "Subject Key ID", + long: "Subject Key Identifier", + }, + }, + "2.5.29.15": { + name: { + short: undefined, + long: "Key Usages", + }, + }, + "2.5.29.17": { + name: { + short: "Subject Alt Names", + long: "Subject Alternative Names", + }, + }, + "2.5.29.19": { + name: { + short: undefined, + long: "Basic Constraints", + }, + }, + "2.5.29.31": { + name: { + short: "CRL Endpoints", + long: "Certificate Revocation List Endpoints", + }, + }, + "2.5.29.32": { + name: { + short: undefined, + long: "Certificate Policies", + }, + }, + "2.5.29.35": { + name: { + short: "Authority Key ID", + long: "Authority Key Identifier", + }, + }, + "2.5.29.37": { + name: { + short: undefined, + long: "Extended Key Usages", + }, + }, + }, + + keyUsages: [ + "CRL Signing", + "Certificate Signing", + "Key Agreement", + "Data Encipherment", + "Key Encipherment", + "Non-Repudiation", + "Digital Signature", + ], + + san: [ + "Other Name", + "RFC 822 Name", + "DNS Name", + "X.400 Address", + "Directory Name", + "EDI Party Name", + "URI", + "IP Address", + "Registered ID", + ], + + eKU: { + "1.3.6.1.4.1.311.10.3.1": "Certificate Trust List (CTL) Signing", + "1.3.6.1.4.1.311.10.3.2": "Timestamp Signing", + "1.3.6.1.4.1.311.10.3.4": "EFS Encryption", + "1.3.6.1.4.1.311.10.3.4.1": "EFS Recovery", + "1.3.6.1.4.1.311.10.3.5": + "Windows Hardware Quality Labs (WHQL) Cryptography", + "1.3.6.1.4.1.311.10.3.7": "Windows NT 5 Cryptography", + "1.3.6.1.4.1.311.10.3.8": "Windows NT Embedded Cryptography", + "1.3.6.1.4.1.311.10.3.10": "Qualified Subordination", + "1.3.6.1.4.1.311.10.3.11": "Escrowed Key Recovery", + "1.3.6.1.4.1.311.10.3.12": "Document Signing", + "1.3.6.1.4.1.311.10.5.1": "Digital Rights Management", + "1.3.6.1.4.1.311.10.6.1": "Key Pack Licenses", + "1.3.6.1.4.1.311.10.6.2": "License Server", + "1.3.6.1.4.1.311.20.2.1": "Enrollment Agent", + "1.3.6.1.4.1.311.20.2.2": "Smartcard Login", + "1.3.6.1.4.1.311.21.5": "Certificate Authority Private Key Archival", + "1.3.6.1.4.1.311.21.6": "Key Recovery Agent", + "1.3.6.1.4.1.311.21.19": "Directory Service Email Replication", + "1.3.6.1.5.5.7.3.1": "Server Authentication", + "1.3.6.1.5.5.7.3.2": "Client Authentication", + "1.3.6.1.5.5.7.3.3": "Code Signing", + "1.3.6.1.5.5.7.3.4": "E-mail Protection", + "1.3.6.1.5.5.7.3.5": "IPsec End System", + "1.3.6.1.5.5.7.3.6": "IPsec Tunnel", + "1.3.6.1.5.5.7.3.7": "IPSec User", + "1.3.6.1.5.5.7.3.8": "Timestamping", + "1.3.6.1.5.5.7.3.9": "OCSP Signing", + "1.3.6.1.5.5.8.2.2": "Internet Key Exchange (IKE)", + }, + + signature: { + "1.2.840.113549.1.1.5": "SHA-1 with RSA Encryption", + "1.2.840.113549.1.1.11": "SHA-256 with RSA Encryption", + "1.2.840.113549.1.1.12": "SHA-384 with RSA Encryption", + "1.2.840.113549.1.1.13": "SHA-512 with RSA Encryption", + "1.2.840.10040.4.3": "DSA with SHA-1", + "2.16.840.1.101.3.4.3.2": "DSA with SHA-256", + "1.2.840.10045.4.1": "ECDSA with SHA-1", + "1.2.840.10045.4.3.2": "ECDSA with SHA-256", + "1.2.840.10045.4.3.3": "ECDSA with SHA-384", + "1.2.840.10045.4.3.4": "ECDSA with SHA-512", + }, + + aia: { + "1.3.6.1.5.5.7.48.1": "Online Certificate Status Protocol (OCSP)", + "1.3.6.1.5.5.7.48.2": "CA Issuers", + }, + + // this includes qualifiers as well + cps: { + "1.3.6.1.4.1": { + name: "Statement Identifier", + value: undefined, + }, + "1.3.6.1.5.5.7.2.1": { + name: "Practices Statement", + value: undefined, + }, + "1.3.6.1.5.5.7.2.2": { + name: "User Notice", + value: undefined, + }, + "2.16.840": { + name: "ANSI Organizational Identifier", + value: undefined, + }, + "2.23.140.1.1": { + name: "Certificate Type", + value: "Extended Validation", + }, + "2.23.140.1.2.1": { + name: "Certificate Type", + value: "Domain Validation", + }, + "2.23.140.1.2.2": { + name: "Certificate Type", + value: "Organization Validation", + }, + "2.23.140.1.2.3": { + name: "Certificate Type", + value: "Individual Validation", + }, + "2.23.140.1.3": { + name: "Certificate Type", + value: "Extended Validation (Code Signing)", + }, + "2.23.140.1.31": { + name: "Certificate Type", + value: ".onion Extended Validation", + }, + "2.23.140.2.1": { + name: "Certificate Type", + value: "Test Certificate", + }, + }, + + microsoftCertificateTypes: { + Administrator: "Administrator", + CA: "Root Certification Authority", + CAExchange: "CA Exchange", + CEPEncryption: "CEP Encryption", + CertificateRequestAgent: "Certificate Request Agent", + ClientAuth: "Authenticated Session", + CodeSigning: "Code Signing", + CrossCA: "Cross Certification Authority", + CTLSigning: "Trust List Signing", + DirectoryEmailReplication: "Directory Email Replication", + DomainController: "Domain Controller", + DomainControllerAuthentication: "Domain Controller Authentication", + EFS: "Basic EFS", + EFSRecovery: "EFS Recovery Agent", + EnrollmentAgent: "Enrollment Agent", + EnrollmentAgentOffline: "Exchange Enrollment Agent (Offline request)", + ExchangeUser: "Exchange User", + ExchangeUserSignature: "Exchange Signature Only", + IPSECIntermediateOffline: "IPSec (Offline request)", + IPSECIntermediateOnline: "IPSEC", + KerberosAuthentication: "Kerberos Authentication", + KeyRecoveryAgent: "Key Recovery Agent", + Machine: "Computer", + MachineEnrollmentAgent: "Enrollment Agent (Computer)", + OCSPResponseSigning: "OCSP Response Signing", + OfflineRouter: "Router (Offline request)", + RASAndIASServer: "RAS and IAS Server", + SmartcardLogon: "Smartcard Logon", + SmartcardUser: "Smartcard User", + SubCA: "Subordinate Certification Authority", + User: "User", + UserSignature: "User Signature Only", + WebServer: "Web Server", + Workstation: "Workstation Authentication", + }, +}; diff --git a/toolkit/components/certviewer/content/utils.js b/toolkit/components/certviewer/content/utils.js new file mode 100644 index 000000000000..abb1e4283341 --- /dev/null +++ b/toolkit/components/certviewer/content/utils.js @@ -0,0 +1,59 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +const { Integer } = asn1js.asn1js; +const { fromBase64, stringToArrayBuffer } = pvutils.pvutils; + +export const b64urltodec = b64 => { + return new Integer({ + valueHex: stringToArrayBuffer(fromBase64("AQAB", true, true)), + }).valueBlock._valueDec; +}; + +export const b64urltohex = b64 => { + const hexBuffer = new Integer({ + valueHex: stringToArrayBuffer(fromBase64(b64, true, true)), + }).valueBlock._valueHex; + const hexArray = Array.from(new Uint8Array(hexBuffer)); + + return hexArray.map(b => ("00" + b.toString(16)).slice(-2)); +}; + +// this particular prototype override makes it easy to chain down complex objects +export const getObjPath = (obj, path) => { + path = path.split("."); + for (let i = 0, len = path.length; i < len; i++) { + if (Array.isArray(obj[path[i]])) { + obj = obj[path[i]][path[i + 1]]; + i++; + } else { + obj = obj[path[i]]; + } + } + return obj; +}; + +export const hash = async (algo, buffer) => { + const hashBuffer = await crypto.subtle.digest(algo, buffer); + const hashArray = Array.from(new Uint8Array(hashBuffer)); + + return hashArray + .map(b => ("00" + b.toString(16)).slice(-2)) + .join(":") + .toUpperCase(); +}; + +export const hashify = hash => { + if (typeof hash === "string") { + return hash + .match(/.{2}/g) + .join(":") + .toUpperCase(); + } + return hash.join(":").toUpperCase(); +}; + +export const pemToDER = pem => { + return stringToArrayBuffer(window.atob(pem)); +}; diff --git a/toolkit/components/certviewer/content/vendor/asn1js_bundle.js b/toolkit/components/certviewer/content/vendor/asn1js_bundle.js new file mode 100644 index 000000000000..8e4dd5f2d984 --- /dev/null +++ b/toolkit/components/certviewer/content/vendor/asn1js_bundle.js @@ -0,0 +1,5877 @@ +(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.asn1js = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + */ +//************************************************************************************** + +const digitsString = "0123456789"; +//************************************************************************************** +//endregion +//************************************************************************************** +//region Declaration for "LocalBaseBlock" class +//************************************************************************************** +/** + * Class used as a base block for all remaining ASN.1 classes + * @typedef LocalBaseBlock + * @interface + * @property {number} blockLength + * @property {string} error + * @property {Array.} warnings + * @property {ArrayBuffer} valueBeforeDecode + */ +class LocalBaseBlock { + //********************************************************************************** + /** + * Constructor for "LocalBaseBlock" class + * @param {Object} [parameters={}] + * @property {ArrayBuffer} [valueBeforeDecode] + */ + constructor(parameters = {}) { + /** + * @type {number} blockLength + */ + this.blockLength = (0, _pvutils.getParametersValue)(parameters, "blockLength", 0); + /** + * @type {string} error + */ + this.error = (0, _pvutils.getParametersValue)(parameters, "error", ""); + /** + * @type {Array.} warnings + */ + this.warnings = (0, _pvutils.getParametersValue)(parameters, "warnings", []); + //noinspection JSCheckFunctionSignatures + /** + * @type {ArrayBuffer} valueBeforeDecode + */ + if ("valueBeforeDecode" in parameters) this.valueBeforeDecode = parameters.valueBeforeDecode.slice(0);else this.valueBeforeDecode = new ArrayBuffer(0); + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "baseBlock"; + } + //********************************************************************************** + /** + * Convertion for the block to JSON object + * @returns {{blockName: string, blockLength: number, error: string, warnings: Array., valueBeforeDecode: string}} + */ + toJSON() { + return { + blockName: this.constructor.blockName(), + blockLength: this.blockLength, + error: this.error, + warnings: this.warnings, + valueBeforeDecode: (0, _pvutils.bufferToHexCodes)(this.valueBeforeDecode, 0, this.valueBeforeDecode.byteLength) + }; + } + //********************************************************************************** +} +//************************************************************************************** +//endregion +//************************************************************************************** +//region Description for "LocalHexBlock" class +//************************************************************************************** +/** + * Class used as a base block for all remaining ASN.1 classes + * @extends LocalBaseBlock + * @typedef LocalHexBlock + * @property {number} blockLength + * @property {string} error + * @property {Array.} warnings + * @property {ArrayBuffer} valueBeforeDecode + * @property {boolean} isHexOnly + * @property {ArrayBuffer} valueHex + */ +//noinspection JSUnusedLocalSymbols +const LocalHexBlock = BaseClass => class LocalHexBlockMixin extends BaseClass { + //********************************************************************************** + //noinspection JSUnusedGlobalSymbols + /** + * Constructor for "LocalHexBlock" class + * @param {Object} [parameters={}] + * @property {ArrayBuffer} [valueHex] + */ + constructor(parameters = {}) { + super(parameters); + + /** + * @type {boolean} + */ + this.isHexOnly = (0, _pvutils.getParametersValue)(parameters, "isHexOnly", false); + /** + * @type {ArrayBuffer} + */ + if ("valueHex" in parameters) this.valueHex = parameters.valueHex.slice(0);else this.valueHex = new ArrayBuffer(0); + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "hexBlock"; + } + //********************************************************************************** + /** + * Base function for converting block from BER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {number} Offset after least decoded byte + */ + fromBER(inputBuffer, inputOffset, inputLength) { + //region Basic check for parameters + //noinspection JSCheckFunctionSignatures + if ((0, _pvutils.checkBufferParams)(this, inputBuffer, inputOffset, inputLength) === false) return -1; + //endregion + + //region Getting Uint8Array from ArrayBuffer + const intBuffer = new Uint8Array(inputBuffer, inputOffset, inputLength); + //endregion + + //region Initial checks + if (intBuffer.length === 0) { + this.warnings.push("Zero buffer length"); + return inputOffset; + } + //endregion + + //region Copy input buffer to internal buffer + this.valueHex = inputBuffer.slice(inputOffset, inputOffset + inputLength); + //endregion + + this.blockLength = inputLength; + + return inputOffset + inputLength; + } + //********************************************************************************** + /** + * Encoding of current ASN.1 block into ASN.1 encoded array (BER rules) + * @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes + * @returns {ArrayBuffer} + */ + toBER(sizeOnly = false) { + if (this.isHexOnly !== true) { + this.error = "Flag \"isHexOnly\" is not set, abort"; + return new ArrayBuffer(0); + } + + if (sizeOnly === true) return new ArrayBuffer(this.valueHex.byteLength); + + //noinspection JSCheckFunctionSignatures + return this.valueHex.slice(0); + } + //********************************************************************************** + /** + * Convertion for the block to JSON object + * @returns {Object} + */ + toJSON() { + let object = {}; + + //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object + try { + object = super.toJSON(); + } catch (ex) {} + //endregion + + object.blockName = this.constructor.blockName(); + object.isHexOnly = this.isHexOnly; + object.valueHex = (0, _pvutils.bufferToHexCodes)(this.valueHex, 0, this.valueHex.byteLength); + + return object; + } + //********************************************************************************** +}; +//************************************************************************************** +//endregion +//************************************************************************************** +//region Declaration of identification block class +//************************************************************************************** +class LocalIdentificationBlock extends LocalHexBlock(LocalBaseBlock) { + //********************************************************************************** + /** + * Constructor for "LocalBaseBlock" class + * @param {Object} [parameters={}] + * @property {Object} [idBlock] + */ + constructor(parameters = {}) { + super(); + + if ("idBlock" in parameters) { + //region Properties from hexBlock class + this.isHexOnly = (0, _pvutils.getParametersValue)(parameters.idBlock, "isHexOnly", false); + this.valueHex = (0, _pvutils.getParametersValue)(parameters.idBlock, "valueHex", new ArrayBuffer(0)); + //endregion + + this.tagClass = (0, _pvutils.getParametersValue)(parameters.idBlock, "tagClass", -1); + this.tagNumber = (0, _pvutils.getParametersValue)(parameters.idBlock, "tagNumber", -1); + this.isConstructed = (0, _pvutils.getParametersValue)(parameters.idBlock, "isConstructed", false); + } else { + this.tagClass = -1; + this.tagNumber = -1; + this.isConstructed = false; + } + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "identificationBlock"; + } + //********************************************************************************** + /** + * Encoding of current ASN.1 block into ASN.1 encoded array (BER rules) + * @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes + * @returns {ArrayBuffer} + */ + toBER(sizeOnly = false) { + //region Initial variables + let firstOctet = 0; + let retBuf; + let retView; + //endregion + + switch (this.tagClass) { + case 1: + firstOctet |= 0x00; // UNIVERSAL + break; + case 2: + firstOctet |= 0x40; // APPLICATION + break; + case 3: + firstOctet |= 0x80; // CONTEXT-SPECIFIC + break; + case 4: + firstOctet |= 0xC0; // PRIVATE + break; + default: + this.error = "Unknown tag class"; + return new ArrayBuffer(0); + } + + if (this.isConstructed) firstOctet |= 0x20; + + if (this.tagNumber < 31 && !this.isHexOnly) { + retBuf = new ArrayBuffer(1); + retView = new Uint8Array(retBuf); + + if (!sizeOnly) { + let number = this.tagNumber; + number &= 0x1F; + firstOctet |= number; + + retView[0] = firstOctet; + } + + return retBuf; + } + + if (this.isHexOnly === false) { + const encodedBuf = (0, _pvutils.utilToBase)(this.tagNumber, 7); + const encodedView = new Uint8Array(encodedBuf); + const size = encodedBuf.byteLength; + + retBuf = new ArrayBuffer(size + 1); + retView = new Uint8Array(retBuf); + retView[0] = firstOctet | 0x1F; + + if (!sizeOnly) { + for (let i = 0; i < size - 1; i++) retView[i + 1] = encodedView[i] | 0x80; + + retView[size] = encodedView[size - 1]; + } + + return retBuf; + } + + retBuf = new ArrayBuffer(this.valueHex.byteLength + 1); + retView = new Uint8Array(retBuf); + + retView[0] = firstOctet | 0x1F; + + if (sizeOnly === false) { + const curView = new Uint8Array(this.valueHex); + + for (let i = 0; i < curView.length - 1; i++) retView[i + 1] = curView[i] | 0x80; + + retView[this.valueHex.byteLength] = curView[curView.length - 1]; + } + + return retBuf; + } + //********************************************************************************** + /** + * Base function for converting block from BER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {number} + */ + fromBER(inputBuffer, inputOffset, inputLength) { + //region Basic check for parameters + //noinspection JSCheckFunctionSignatures + if ((0, _pvutils.checkBufferParams)(this, inputBuffer, inputOffset, inputLength) === false) return -1; + //endregion + + //region Getting Uint8Array from ArrayBuffer + const intBuffer = new Uint8Array(inputBuffer, inputOffset, inputLength); + //endregion + + //region Initial checks + if (intBuffer.length === 0) { + this.error = "Zero buffer length"; + return -1; + } + //endregion + + //region Find tag class + const tagClassMask = intBuffer[0] & 0xC0; + + switch (tagClassMask) { + case 0x00: + this.tagClass = 1; // UNIVERSAL + break; + case 0x40: + this.tagClass = 2; // APPLICATION + break; + case 0x80: + this.tagClass = 3; // CONTEXT-SPECIFIC + break; + case 0xC0: + this.tagClass = 4; // PRIVATE + break; + default: + this.error = "Unknown tag class"; + return -1; + } + //endregion + + //region Find it's constructed or not + this.isConstructed = (intBuffer[0] & 0x20) === 0x20; + //endregion + + //region Find tag number + this.isHexOnly = false; + + const tagNumberMask = intBuffer[0] & 0x1F; + + //region Simple case (tag number < 31) + if (tagNumberMask !== 0x1F) { + this.tagNumber = tagNumberMask; + this.blockLength = 1; + } + //endregion + //region Tag number bigger or equal to 31 + else { + let count = 1; + + this.valueHex = new ArrayBuffer(255); + let tagNumberBufferMaxLength = 255; + let intTagNumberBuffer = new Uint8Array(this.valueHex); + + //noinspection JSBitwiseOperatorUsage + while (intBuffer[count] & 0x80) { + intTagNumberBuffer[count - 1] = intBuffer[count] & 0x7F; + count++; + + if (count >= intBuffer.length) { + this.error = "End of input reached before message was fully decoded"; + return -1; + } + + //region In case if tag number length is greater than 255 bytes (rare but possible case) + if (count === tagNumberBufferMaxLength) { + tagNumberBufferMaxLength += 255; + + const tempBuffer = new ArrayBuffer(tagNumberBufferMaxLength); + const tempBufferView = new Uint8Array(tempBuffer); + + for (let i = 0; i < intTagNumberBuffer.length; i++) tempBufferView[i] = intTagNumberBuffer[i]; + + this.valueHex = new ArrayBuffer(tagNumberBufferMaxLength); + intTagNumberBuffer = new Uint8Array(this.valueHex); + } + //endregion + } + + this.blockLength = count + 1; + intTagNumberBuffer[count - 1] = intBuffer[count] & 0x7F; // Write last byte to buffer + + //region Cut buffer + const tempBuffer = new ArrayBuffer(count); + const tempBufferView = new Uint8Array(tempBuffer); + + for (let i = 0; i < count; i++) tempBufferView[i] = intTagNumberBuffer[i]; + + this.valueHex = new ArrayBuffer(count); + intTagNumberBuffer = new Uint8Array(this.valueHex); + intTagNumberBuffer.set(tempBufferView); + //endregion + + //region Try to convert long tag number to short form + if (this.blockLength <= 9) this.tagNumber = (0, _pvutils.utilFromBase)(intTagNumberBuffer, 7);else { + this.isHexOnly = true; + this.warnings.push("Tag too long, represented as hex-coded"); + } + //endregion + } + //endregion + //endregion + + //region Check if constructed encoding was using for primitive type + if (this.tagClass === 1 && this.isConstructed) { + switch (this.tagNumber) { + case 1: // Boolean + case 2: // REAL + case 5: // Null + case 6: // OBJECT IDENTIFIER + case 9: // REAL + case 14: // Time + case 23: + case 24: + case 31: + case 32: + case 33: + case 34: + this.error = "Constructed encoding used for primitive type"; + return -1; + default: + } + } + //endregion + + return inputOffset + this.blockLength; // Return current offset in input buffer + } + //********************************************************************************** + /** + * Convertion for the block to JSON object + * @returns {{blockName: string, + * tagClass: number, + * tagNumber: number, + * isConstructed: boolean, + * isHexOnly: boolean, + * valueHex: ArrayBuffer, + * blockLength: number, + * error: string, warnings: Array., + * valueBeforeDecode: string}} + */ + toJSON() { + let object = {}; + + //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object + try { + object = super.toJSON(); + } catch (ex) {} + //endregion + + object.blockName = this.constructor.blockName(); + object.tagClass = this.tagClass; + object.tagNumber = this.tagNumber; + object.isConstructed = this.isConstructed; + + return object; + } + //********************************************************************************** +} +//************************************************************************************** +//endregion +//************************************************************************************** +//region Declaration of length block class +//************************************************************************************** +class LocalLengthBlock extends LocalBaseBlock { + //********************************************************************************** + /** + * Constructor for "LocalLengthBlock" class + * @param {Object} [parameters={}] + * @property {Object} [lenBlock] + */ + constructor(parameters = {}) { + super(); + + if ("lenBlock" in parameters) { + this.isIndefiniteForm = (0, _pvutils.getParametersValue)(parameters.lenBlock, "isIndefiniteForm", false); + this.longFormUsed = (0, _pvutils.getParametersValue)(parameters.lenBlock, "longFormUsed", false); + this.length = (0, _pvutils.getParametersValue)(parameters.lenBlock, "length", 0); + } else { + this.isIndefiniteForm = false; + this.longFormUsed = false; + this.length = 0; + } + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "lengthBlock"; + } + //********************************************************************************** + /** + * Base function for converting block from BER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {number} + */ + fromBER(inputBuffer, inputOffset, inputLength) { + //region Basic check for parameters + //noinspection JSCheckFunctionSignatures + if ((0, _pvutils.checkBufferParams)(this, inputBuffer, inputOffset, inputLength) === false) return -1; + //endregion + + //region Getting Uint8Array from ArrayBuffer + const intBuffer = new Uint8Array(inputBuffer, inputOffset, inputLength); + //endregion + + //region Initial checks + if (intBuffer.length === 0) { + this.error = "Zero buffer length"; + return -1; + } + + if (intBuffer[0] === 0xFF) { + this.error = "Length block 0xFF is reserved by standard"; + return -1; + } + //endregion + + //region Check for length form type + this.isIndefiniteForm = intBuffer[0] === 0x80; + //endregion + + //region Stop working in case of indefinite length form + if (this.isIndefiniteForm === true) { + this.blockLength = 1; + return inputOffset + this.blockLength; + } + //endregion + + //region Check is long form of length encoding using + this.longFormUsed = !!(intBuffer[0] & 0x80); + //endregion + + //region Stop working in case of short form of length value + if (this.longFormUsed === false) { + this.length = intBuffer[0]; + this.blockLength = 1; + return inputOffset + this.blockLength; + } + //endregion + + //region Calculate length value in case of long form + const count = intBuffer[0] & 0x7F; + + if (count > 8) // Too big length value + { + this.error = "Too big integer"; + return -1; + } + + if (count + 1 > intBuffer.length) { + this.error = "End of input reached before message was fully decoded"; + return -1; + } + + const lengthBufferView = new Uint8Array(count); + + for (let i = 0; i < count; i++) lengthBufferView[i] = intBuffer[i + 1]; + + if (lengthBufferView[count - 1] === 0x00) this.warnings.push("Needlessly long encoded length"); + + this.length = (0, _pvutils.utilFromBase)(lengthBufferView, 8); + + if (this.longFormUsed && this.length <= 127) this.warnings.push("Unneccesary usage of long length form"); + + this.blockLength = count + 1; + //endregion + + return inputOffset + this.blockLength; // Return current offset in input buffer + } + //********************************************************************************** + /** + * Encoding of current ASN.1 block into ASN.1 encoded array (BER rules) + * @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes + * @returns {ArrayBuffer} + */ + toBER(sizeOnly = false) { + //region Initial variables + let retBuf; + let retView; + //endregion + + if (this.length > 127) this.longFormUsed = true; + + if (this.isIndefiniteForm) { + retBuf = new ArrayBuffer(1); + + if (sizeOnly === false) { + retView = new Uint8Array(retBuf); + retView[0] = 0x80; + } + + return retBuf; + } + + if (this.longFormUsed === true) { + const encodedBuf = (0, _pvutils.utilToBase)(this.length, 8); + + if (encodedBuf.byteLength > 127) { + this.error = "Too big length"; + return new ArrayBuffer(0); + } + + retBuf = new ArrayBuffer(encodedBuf.byteLength + 1); + + if (sizeOnly === true) return retBuf; + + const encodedView = new Uint8Array(encodedBuf); + retView = new Uint8Array(retBuf); + + retView[0] = encodedBuf.byteLength | 0x80; + + for (let i = 0; i < encodedBuf.byteLength; i++) retView[i + 1] = encodedView[i]; + + return retBuf; + } + + retBuf = new ArrayBuffer(1); + + if (sizeOnly === false) { + retView = new Uint8Array(retBuf); + + retView[0] = this.length; + } + + return retBuf; + } + //********************************************************************************** + /** + * Convertion for the block to JSON object + * @returns {{blockName, blockLength, error, warnings, valueBeforeDecode}|{blockName: string, blockLength: number, error: string, warnings: Array., valueBeforeDecode: string}} + */ + toJSON() { + let object = {}; + + //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object + try { + object = super.toJSON(); + } catch (ex) {} + //endregion + + object.blockName = this.constructor.blockName(); + object.isIndefiniteForm = this.isIndefiniteForm; + object.longFormUsed = this.longFormUsed; + object.length = this.length; + + return object; + } + //********************************************************************************** +} +//************************************************************************************** +//endregion +//************************************************************************************** +//region Declaration of value block class +//************************************************************************************** +class LocalValueBlock extends LocalBaseBlock { + //********************************************************************************** + /** + * Constructor for "LocalValueBlock" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) { + super(parameters); + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "valueBlock"; + } + //********************************************************************************** + //noinspection JSUnusedLocalSymbols,JSUnusedLocalSymbols,JSUnusedLocalSymbols + /** + * Base function for converting block from BER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {number} + */ + fromBER(inputBuffer, inputOffset, inputLength) { + //region Throw an exception for a function which needs to be specified in extended classes + throw TypeError("User need to make a specific function in a class which extends \"LocalValueBlock\""); + //endregion + } + //********************************************************************************** + //noinspection JSUnusedLocalSymbols + /** + * Encoding of current ASN.1 block into ASN.1 encoded array (BER rules) + * @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes + * @returns {ArrayBuffer} + */ + toBER(sizeOnly = false) { + //region Throw an exception for a function which needs to be specified in extended classes + throw TypeError("User need to make a specific function in a class which extends \"LocalValueBlock\""); + //endregion + } + //********************************************************************************** +} +//************************************************************************************** +//endregion +//************************************************************************************** +//region Declaration of basic ASN.1 block class +//************************************************************************************** +class BaseBlock extends LocalBaseBlock { + //********************************************************************************** + /** + * Constructor for "BaseBlock" class + * @param {Object} [parameters={}] + * @property {Object} [primitiveSchema] + * @property {string} [name] + * @property {boolean} [optional] + * @param valueBlockType Type of value block + */ + constructor(parameters = {}, valueBlockType = LocalValueBlock) { + super(parameters); + + if ("name" in parameters) this.name = parameters.name; + if ("optional" in parameters) this.optional = parameters.optional; + if ("primitiveSchema" in parameters) this.primitiveSchema = parameters.primitiveSchema; + + this.idBlock = new LocalIdentificationBlock(parameters); + this.lenBlock = new LocalLengthBlock(parameters); + this.valueBlock = new valueBlockType(parameters); + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "BaseBlock"; + } + //********************************************************************************** + /** + * Base function for converting block from BER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {number} + */ + fromBER(inputBuffer, inputOffset, inputLength) { + const resultOffset = this.valueBlock.fromBER(inputBuffer, inputOffset, this.lenBlock.isIndefiniteForm === true ? inputLength : this.lenBlock.length); + if (resultOffset === -1) { + this.error = this.valueBlock.error; + return resultOffset; + } + + if (this.idBlock.error.length === 0) this.blockLength += this.idBlock.blockLength; + + if (this.lenBlock.error.length === 0) this.blockLength += this.lenBlock.blockLength; + + if (this.valueBlock.error.length === 0) this.blockLength += this.valueBlock.blockLength; + + return resultOffset; + } + //********************************************************************************** + /** + * Encoding of current ASN.1 block into ASN.1 encoded array (BER rules) + * @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes + * @returns {ArrayBuffer} + */ + toBER(sizeOnly = false) { + let retBuf; + + const idBlockBuf = this.idBlock.toBER(sizeOnly); + const valueBlockSizeBuf = this.valueBlock.toBER(true); + + this.lenBlock.length = valueBlockSizeBuf.byteLength; + const lenBlockBuf = this.lenBlock.toBER(sizeOnly); + + retBuf = (0, _pvutils.utilConcatBuf)(idBlockBuf, lenBlockBuf); + + let valueBlockBuf; + + if (sizeOnly === false) valueBlockBuf = this.valueBlock.toBER(sizeOnly);else valueBlockBuf = new ArrayBuffer(this.lenBlock.length); + + retBuf = (0, _pvutils.utilConcatBuf)(retBuf, valueBlockBuf); + + if (this.lenBlock.isIndefiniteForm === true) { + const indefBuf = new ArrayBuffer(2); + + if (sizeOnly === false) { + const indefView = new Uint8Array(indefBuf); + + indefView[0] = 0x00; + indefView[1] = 0x00; + } + + retBuf = (0, _pvutils.utilConcatBuf)(retBuf, indefBuf); + } + + return retBuf; + } + //********************************************************************************** + /** + * Convertion for the block to JSON object + * @returns {{blockName, blockLength, error, warnings, valueBeforeDecode}|{blockName: string, blockLength: number, error: string, warnings: Array., valueBeforeDecode: string}} + */ + toJSON() { + let object = {}; + + //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object + try { + object = super.toJSON(); + } catch (ex) {} + //endregion + + object.idBlock = this.idBlock.toJSON(); + object.lenBlock = this.lenBlock.toJSON(); + object.valueBlock = this.valueBlock.toJSON(); + + if ("name" in this) object.name = this.name; + if ("optional" in this) object.optional = this.optional; + if ("primitiveSchema" in this) object.primitiveSchema = this.primitiveSchema.toJSON(); + + return object; + } + //********************************************************************************** +} +exports.BaseBlock = BaseBlock; //************************************************************************************** +//endregion +//************************************************************************************** +//region Declaration of basic block for all PRIMITIVE types +//************************************************************************************** + +class LocalPrimitiveValueBlock extends LocalValueBlock { + //********************************************************************************** + /** + * Constructor for "LocalPrimitiveValueBlock" class + * @param {Object} [parameters={}] + * @property {ArrayBuffer} [valueBeforeDecode] + */ + constructor(parameters = {}) { + super(parameters); + + //region Variables from "hexBlock" class + if ("valueHex" in parameters) this.valueHex = parameters.valueHex.slice(0);else this.valueHex = new ArrayBuffer(0); + + this.isHexOnly = (0, _pvutils.getParametersValue)(parameters, "isHexOnly", true); + //endregion + } + //********************************************************************************** + /** + * Base function for converting block from BER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {number} + */ + fromBER(inputBuffer, inputOffset, inputLength) { + //region Basic check for parameters + //noinspection JSCheckFunctionSignatures + if ((0, _pvutils.checkBufferParams)(this, inputBuffer, inputOffset, inputLength) === false) return -1; + //endregion + + //region Getting Uint8Array from ArrayBuffer + const intBuffer = new Uint8Array(inputBuffer, inputOffset, inputLength); + //endregion + + //region Initial checks + if (intBuffer.length === 0) { + this.warnings.push("Zero buffer length"); + return inputOffset; + } + //endregion + + //region Copy input buffer into internal buffer + this.valueHex = new ArrayBuffer(intBuffer.length); + const valueHexView = new Uint8Array(this.valueHex); + + for (let i = 0; i < intBuffer.length; i++) valueHexView[i] = intBuffer[i]; + //endregion + + this.blockLength = inputLength; + + return inputOffset + inputLength; + } + //********************************************************************************** + //noinspection JSUnusedLocalSymbols + /** + * Encoding of current ASN.1 block into ASN.1 encoded array (BER rules) + * @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes + * @returns {ArrayBuffer} + */ + toBER(sizeOnly = false) { + return this.valueHex.slice(0); + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "PrimitiveValueBlock"; + } + //********************************************************************************** + /** + * Convertion for the block to JSON object + * @returns {{blockName, blockLength, error, warnings, valueBeforeDecode}|{blockName: string, blockLength: number, error: string, warnings: Array., valueBeforeDecode: string}} + */ + toJSON() { + let object = {}; + + //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object + try { + object = super.toJSON(); + } catch (ex) {} + //endregion + + object.valueHex = (0, _pvutils.bufferToHexCodes)(this.valueHex, 0, this.valueHex.byteLength); + object.isHexOnly = this.isHexOnly; + + return object; + } + //********************************************************************************** +} +//************************************************************************************** +class Primitive extends BaseBlock { + //********************************************************************************** + /** + * Constructor for "Primitive" class + * @param {Object} [parameters={}] + * @property {ArrayBuffer} [valueHex] + */ + constructor(parameters = {}) { + super(parameters, LocalPrimitiveValueBlock); + + this.idBlock.isConstructed = false; + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "PRIMITIVE"; + } + //********************************************************************************** +} +exports.Primitive = Primitive; //************************************************************************************** +//endregion +//************************************************************************************** +//region Declaration of basic block for all CONSTRUCTED types +//************************************************************************************** + +class LocalConstructedValueBlock extends LocalValueBlock { + //********************************************************************************** + /** + * Constructor for "LocalConstructedValueBlock" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) { + super(parameters); + + this.value = (0, _pvutils.getParametersValue)(parameters, "value", []); + this.isIndefiniteForm = (0, _pvutils.getParametersValue)(parameters, "isIndefiniteForm", false); + } + //********************************************************************************** + /** + * Base function for converting block from BER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {number} + */ + fromBER(inputBuffer, inputOffset, inputLength) { + //region Store initial offset and length + const initialOffset = inputOffset; + const initialLength = inputLength; + //endregion + + //region Basic check for parameters + //noinspection JSCheckFunctionSignatures + if ((0, _pvutils.checkBufferParams)(this, inputBuffer, inputOffset, inputLength) === false) return -1; + //endregion + + //region Getting Uint8Array from ArrayBuffer + const intBuffer = new Uint8Array(inputBuffer, inputOffset, inputLength); + //endregion + + //region Initial checks + if (intBuffer.length === 0) { + this.warnings.push("Zero buffer length"); + return inputOffset; + } + //endregion + + //region Aux function + function checkLen(indefiniteLength, length) { + if (indefiniteLength === true) return 1; + + return length; + } + //endregion + + let currentOffset = inputOffset; + + while (checkLen(this.isIndefiniteForm, inputLength) > 0) { + const returnObject = LocalFromBER(inputBuffer, currentOffset, inputLength); + if (returnObject.offset === -1) { + this.error = returnObject.result.error; + this.warnings.concat(returnObject.result.warnings); + return -1; + } + + currentOffset = returnObject.offset; + + this.blockLength += returnObject.result.blockLength; + inputLength -= returnObject.result.blockLength; + + this.value.push(returnObject.result); + + if (this.isIndefiniteForm === true && returnObject.result.constructor.blockName() === EndOfContent.blockName()) break; + } + + if (this.isIndefiniteForm === true) { + if (this.value[this.value.length - 1].constructor.blockName() === EndOfContent.blockName()) this.value.pop();else this.warnings.push("No EndOfContent block encoded"); + } + + //region Copy "inputBuffer" to "valueBeforeDecode" + this.valueBeforeDecode = inputBuffer.slice(initialOffset, initialOffset + initialLength); + //endregion + + return currentOffset; + } + //********************************************************************************** + /** + * Encoding of current ASN.1 block into ASN.1 encoded array (BER rules) + * @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes + * @returns {ArrayBuffer} + */ + toBER(sizeOnly = false) { + let retBuf = new ArrayBuffer(0); + + for (let i = 0; i < this.value.length; i++) { + const valueBuf = this.value[i].toBER(sizeOnly); + retBuf = (0, _pvutils.utilConcatBuf)(retBuf, valueBuf); + } + + return retBuf; + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "ConstructedValueBlock"; + } + //********************************************************************************** + /** + * Convertion for the block to JSON object + * @returns {{blockName, blockLength, error, warnings, valueBeforeDecode}|{blockName: string, blockLength: number, error: string, warnings: Array., valueBeforeDecode: string}} + */ + toJSON() { + let object = {}; + + //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object + try { + object = super.toJSON(); + } catch (ex) {} + //endregion + + object.isIndefiniteForm = this.isIndefiniteForm; + object.value = []; + for (let i = 0; i < this.value.length; i++) object.value.push(this.value[i].toJSON()); + + return object; + } + //********************************************************************************** +} +//************************************************************************************** +class Constructed extends BaseBlock { + //********************************************************************************** + /** + * Constructor for "Constructed" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) { + super(parameters, LocalConstructedValueBlock); + + this.idBlock.isConstructed = true; + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "CONSTRUCTED"; + } + //********************************************************************************** + /** + * Base function for converting block from BER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {number} + */ + fromBER(inputBuffer, inputOffset, inputLength) { + this.valueBlock.isIndefiniteForm = this.lenBlock.isIndefiniteForm; + + const resultOffset = this.valueBlock.fromBER(inputBuffer, inputOffset, this.lenBlock.isIndefiniteForm === true ? inputLength : this.lenBlock.length); + if (resultOffset === -1) { + this.error = this.valueBlock.error; + return resultOffset; + } + + if (this.idBlock.error.length === 0) this.blockLength += this.idBlock.blockLength; + + if (this.lenBlock.error.length === 0) this.blockLength += this.lenBlock.blockLength; + + if (this.valueBlock.error.length === 0) this.blockLength += this.valueBlock.blockLength; + + return resultOffset; + } + //********************************************************************************** +} +exports.Constructed = Constructed; //************************************************************************************** +//endregion +//************************************************************************************** +//region Declaration of ASN.1 EndOfContent type class +//************************************************************************************** + +class LocalEndOfContentValueBlock extends LocalValueBlock { + //********************************************************************************** + /** + * Constructor for "LocalEndOfContentValueBlock" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) { + super(parameters); + } + //********************************************************************************** + //noinspection JSUnusedLocalSymbols,JSUnusedLocalSymbols + /** + * Base function for converting block from BER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {number} + */ + fromBER(inputBuffer, inputOffset, inputLength) { + //region There is no "value block" for EndOfContent type and we need to return the same offset + return inputOffset; + //endregion + } + //********************************************************************************** + //noinspection JSUnusedLocalSymbols + /** + * Encoding of current ASN.1 block into ASN.1 encoded array (BER rules) + * @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes + * @returns {ArrayBuffer} + */ + toBER(sizeOnly = false) { + return new ArrayBuffer(0); + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "EndOfContentValueBlock"; + } + //********************************************************************************** +} +//************************************************************************************** +class EndOfContent extends BaseBlock { + //********************************************************************************** + constructor(paramaters = {}) { + super(paramaters, LocalEndOfContentValueBlock); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 0; // EndOfContent + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "EndOfContent"; + } + //********************************************************************************** +} +exports.EndOfContent = EndOfContent; //************************************************************************************** +//endregion +//************************************************************************************** +//region Declaration of ASN.1 Boolean type class +//************************************************************************************** + +class LocalBooleanValueBlock extends LocalValueBlock { + //********************************************************************************** + /** + * Constructor for "LocalBooleanValueBlock" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) { + super(parameters); + + this.value = (0, _pvutils.getParametersValue)(parameters, "value", false); + this.isHexOnly = (0, _pvutils.getParametersValue)(parameters, "isHexOnly", false); + + if ("valueHex" in parameters) this.valueHex = parameters.valueHex.slice(0);else { + this.valueHex = new ArrayBuffer(1); + if (this.value === true) { + const view = new Uint8Array(this.valueHex); + view[0] = 0xFF; + } + } + } + //********************************************************************************** + /** + * Base function for converting block from BER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {number} Offset after least decoded byte + */ + fromBER(inputBuffer, inputOffset, inputLength) { + //region Basic check for parameters + //noinspection JSCheckFunctionSignatures + if ((0, _pvutils.checkBufferParams)(this, inputBuffer, inputOffset, inputLength) === false) return -1; + //endregion + + //region Getting Uint8Array from ArrayBuffer + const intBuffer = new Uint8Array(inputBuffer, inputOffset, inputLength); + //endregion + + if (inputLength > 1) this.warnings.push("Boolean value encoded in more then 1 octet"); + + this.isHexOnly = true; + + //region Copy input buffer to internal array + this.valueHex = new ArrayBuffer(intBuffer.length); + const view = new Uint8Array(this.valueHex); + + for (let i = 0; i < intBuffer.length; i++) view[i] = intBuffer[i]; + //endregion + + if (_pvutils.utilDecodeTC.call(this) !== 0) this.value = true;else this.value = false; + + this.blockLength = inputLength; + + return inputOffset + inputLength; + } + //********************************************************************************** + //noinspection JSUnusedLocalSymbols + /** + * Encoding of current ASN.1 block into ASN.1 encoded array (BER rules) + * @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes + * @returns {ArrayBuffer} + */ + toBER(sizeOnly = false) { + return this.valueHex; + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "BooleanValueBlock"; + } + //********************************************************************************** + /** + * Convertion for the block to JSON object + * @returns {{blockName, blockLength, error, warnings, valueBeforeDecode}|{blockName: string, blockLength: number, error: string, warnings: Array., valueBeforeDecode: string}} + */ + toJSON() { + let object = {}; + + //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object + try { + object = super.toJSON(); + } catch (ex) {} + //endregion + + object.value = this.value; + object.isHexOnly = this.isHexOnly; + object.valueHex = (0, _pvutils.bufferToHexCodes)(this.valueHex, 0, this.valueHex.byteLength); + + return object; + } + //********************************************************************************** +} +//************************************************************************************** +class Boolean extends BaseBlock { + //********************************************************************************** + /** + * Constructor for "Boolean" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) { + super(parameters, LocalBooleanValueBlock); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 1; // Boolean + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "Boolean"; + } + //********************************************************************************** +} +exports.Boolean = Boolean; //************************************************************************************** +//endregion +//************************************************************************************** +//region Declaration of ASN.1 Sequence and Set type classes +//************************************************************************************** + +class Sequence extends Constructed { + //********************************************************************************** + /** + * Constructor for "Sequence" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) { + super(parameters); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 16; // Sequence + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "Sequence"; + } + //********************************************************************************** +} +exports.Sequence = Sequence; //************************************************************************************** + +class Set extends Constructed { + //********************************************************************************** + /** + * Constructor for "Set" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) { + super(parameters); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 17; // Set + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "Set"; + } + //********************************************************************************** +} +exports.Set = Set; //************************************************************************************** +//endregion +//************************************************************************************** +//region Declaration of ASN.1 Null type class +//************************************************************************************** + +class Null extends BaseBlock { + //********************************************************************************** + /** + * Constructor for "Null" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) { + super(parameters, LocalBaseBlock); // We will not have a call to "Null value block" because of specified "fromBER" and "toBER" functions + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 5; // Null + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "Null"; + } + //********************************************************************************** + //noinspection JSUnusedLocalSymbols + /** + * Base function for converting block from BER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {number} Offset after least decoded byte + */ + fromBER(inputBuffer, inputOffset, inputLength) { + if (this.lenBlock.length > 0) this.warnings.push("Non-zero length of value block for Null type"); + + if (this.idBlock.error.length === 0) this.blockLength += this.idBlock.blockLength; + + if (this.lenBlock.error.length === 0) this.blockLength += this.lenBlock.blockLength; + + this.blockLength += inputLength; + + if (inputOffset + inputLength > inputBuffer.byteLength) { + this.error = "End of input reached before message was fully decoded (inconsistent offset and length values)"; + return -1; + } + + return inputOffset + inputLength; + } + //********************************************************************************** + /** + * Encoding of current ASN.1 block into ASN.1 encoded array (BER rules) + * @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes + * @returns {ArrayBuffer} + */ + toBER(sizeOnly = false) { + const retBuf = new ArrayBuffer(2); + + if (sizeOnly === true) return retBuf; + + const retView = new Uint8Array(retBuf); + retView[0] = 0x05; + retView[1] = 0x00; + + return retBuf; + } + //********************************************************************************** +} +exports.Null = Null; //************************************************************************************** +//endregion +//************************************************************************************** +//region Declaration of ASN.1 OctetString type class +//************************************************************************************** + +class LocalOctetStringValueBlock extends LocalHexBlock(LocalConstructedValueBlock) { + //********************************************************************************** + /** + * Constructor for "LocalOctetStringValueBlock" class + * @param {Object} [parameters={}] + * @property {ArrayBuffer} [valueHex] + */ + constructor(parameters = {}) { + super(parameters); + + this.isConstructed = (0, _pvutils.getParametersValue)(parameters, "isConstructed", false); + } + //********************************************************************************** + /** + * Base function for converting block from BER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {number} Offset after least decoded byte + */ + fromBER(inputBuffer, inputOffset, inputLength) { + let resultOffset = 0; + + if (this.isConstructed === true) { + this.isHexOnly = false; + + resultOffset = LocalConstructedValueBlock.prototype.fromBER.call(this, inputBuffer, inputOffset, inputLength); + if (resultOffset === -1) return resultOffset; + + for (let i = 0; i < this.value.length; i++) { + const currentBlockName = this.value[i].constructor.blockName(); + + if (currentBlockName === EndOfContent.blockName()) { + if (this.isIndefiniteForm === true) break;else { + this.error = "EndOfContent is unexpected, OCTET STRING may consists of OCTET STRINGs only"; + return -1; + } + } + + if (currentBlockName !== OctetString.blockName()) { + this.error = "OCTET STRING may consists of OCTET STRINGs only"; + return -1; + } + } + } else { + this.isHexOnly = true; + + resultOffset = super.fromBER(inputBuffer, inputOffset, inputLength); + this.blockLength = inputLength; + } + + return resultOffset; + } + //********************************************************************************** + /** + * Encoding of current ASN.1 block into ASN.1 encoded array (BER rules) + * @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes + * @returns {ArrayBuffer} + */ + toBER(sizeOnly = false) { + if (this.isConstructed === true) return LocalConstructedValueBlock.prototype.toBER.call(this, sizeOnly); + + let retBuf = new ArrayBuffer(this.valueHex.byteLength); + + if (sizeOnly === true) return retBuf; + + if (this.valueHex.byteLength === 0) return retBuf; + + retBuf = this.valueHex.slice(0); + + return retBuf; + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "OctetStringValueBlock"; + } + //********************************************************************************** + toJSON() { + let object = {}; + + //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object + try { + object = super.toJSON(); + } catch (ex) {} + //endregion + + object.isConstructed = this.isConstructed; + object.isHexOnly = this.isHexOnly; + object.valueHex = (0, _pvutils.bufferToHexCodes)(this.valueHex, 0, this.valueHex.byteLength); + + return object; + } + //********************************************************************************** +} +//************************************************************************************** +class OctetString extends BaseBlock { + //********************************************************************************** + /** + * Constructor for "OctetString" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) { + super(parameters, LocalOctetStringValueBlock); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 4; // OctetString + } + //********************************************************************************** + /** + * Base function for converting block from BER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {number} Offset after least decoded byte + */ + fromBER(inputBuffer, inputOffset, inputLength) { + this.valueBlock.isConstructed = this.idBlock.isConstructed; + this.valueBlock.isIndefiniteForm = this.lenBlock.isIndefiniteForm; + + //region Ability to encode empty OCTET STRING + if (inputLength === 0) { + if (this.idBlock.error.length === 0) this.blockLength += this.idBlock.blockLength; + + if (this.lenBlock.error.length === 0) this.blockLength += this.lenBlock.blockLength; + + return inputOffset; + } + //endregion + + return super.fromBER(inputBuffer, inputOffset, inputLength); + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "OctetString"; + } + //********************************************************************************** + //noinspection JSUnusedGlobalSymbols + /** + * Checking that two OCTETSTRINGs are equal + * @param {OctetString} octetString + */ + isEqual(octetString) { + //region Check input type + if (octetString instanceof OctetString === false) return false; + //endregion + + //region Compare two JSON strings + if (JSON.stringify(this) !== JSON.stringify(octetString)) return false; + //endregion + + return true; + } + //********************************************************************************** +} +exports.OctetString = OctetString; //************************************************************************************** +//endregion +//************************************************************************************** +//region Declaration of ASN.1 BitString type class +//************************************************************************************** + +class LocalBitStringValueBlock extends LocalHexBlock(LocalConstructedValueBlock) { + //********************************************************************************** + /** + * Constructor for "LocalBitStringValueBlock" class + * @param {Object} [parameters={}] + * @property {ArrayBuffer} [valueHex] + */ + constructor(parameters = {}) { + super(parameters); + + this.unusedBits = (0, _pvutils.getParametersValue)(parameters, "unusedBits", 0); + this.isConstructed = (0, _pvutils.getParametersValue)(parameters, "isConstructed", false); + this.blockLength = this.valueHex.byteLength; + } + //********************************************************************************** + /** + * Base function for converting block from BER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {number} Offset after least decoded byte + */ + fromBER(inputBuffer, inputOffset, inputLength) { + //region Ability to decode zero-length BitString value + if (inputLength === 0) return inputOffset; + //endregion + + let resultOffset = -1; + + //region If the BISTRING supposed to be a constructed value + if (this.isConstructed === true) { + resultOffset = LocalConstructedValueBlock.prototype.fromBER.call(this, inputBuffer, inputOffset, inputLength); + if (resultOffset === -1) return resultOffset; + + for (let i = 0; i < this.value.length; i++) { + const currentBlockName = this.value[i].constructor.blockName(); + + if (currentBlockName === EndOfContent.blockName()) { + if (this.isIndefiniteForm === true) break;else { + this.error = "EndOfContent is unexpected, BIT STRING may consists of BIT STRINGs only"; + return -1; + } + } + + if (currentBlockName !== BitString.blockName()) { + this.error = "BIT STRING may consists of BIT STRINGs only"; + return -1; + } + + if (this.unusedBits > 0 && this.value[i].valueBlock.unusedBits > 0) { + this.error = "Usign of \"unused bits\" inside constructive BIT STRING allowed for least one only"; + return -1; + } + + this.unusedBits = this.value[i].valueBlock.unusedBits; + if (this.unusedBits > 7) { + this.error = "Unused bits for BitString must be in range 0-7"; + return -1; + } + } + + return resultOffset; + } + //endregion + //region If the BitString supposed to be a primitive value + //region Basic check for parameters + //noinspection JSCheckFunctionSignatures + if ((0, _pvutils.checkBufferParams)(this, inputBuffer, inputOffset, inputLength) === false) return -1; + //endregion + + const intBuffer = new Uint8Array(inputBuffer, inputOffset, inputLength); + + this.unusedBits = intBuffer[0]; + + if (this.unusedBits > 7) { + this.error = "Unused bits for BitString must be in range 0-7"; + return -1; + } + + //region Copy input buffer to internal buffer + this.valueHex = new ArrayBuffer(intBuffer.length - 1); + const view = new Uint8Array(this.valueHex); + for (let i = 0; i < inputLength - 1; i++) view[i] = intBuffer[i + 1]; + //endregion + + this.blockLength = intBuffer.length; + + return inputOffset + inputLength; + //endregion + } + //********************************************************************************** + /** + * Encoding of current ASN.1 block into ASN.1 encoded array (BER rules) + * @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes + * @returns {ArrayBuffer} + */ + toBER(sizeOnly = false) { + if (this.isConstructed === true) return LocalConstructedValueBlock.prototype.toBER.call(this, sizeOnly); + + if (sizeOnly === true) return new ArrayBuffer(this.valueHex.byteLength + 1); + + if (this.valueHex.byteLength === 0) return new ArrayBuffer(0); + + const curView = new Uint8Array(this.valueHex); + + const retBuf = new ArrayBuffer(this.valueHex.byteLength + 1); + const retView = new Uint8Array(retBuf); + + retView[0] = this.unusedBits; + + for (let i = 0; i < this.valueHex.byteLength; i++) retView[i + 1] = curView[i]; + + return retBuf; + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "BitStringValueBlock"; + } + //********************************************************************************** + /** + * Convertion for the block to JSON object + * @returns {{blockName, blockLength, error, warnings, valueBeforeDecode}|{blockName: string, blockLength: number, error: string, warnings: Array., valueBeforeDecode: string}} + */ + toJSON() { + let object = {}; + + //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object + try { + object = super.toJSON(); + } catch (ex) {} + //endregion + + object.unusedBits = this.unusedBits; + object.isConstructed = this.isConstructed; + object.isHexOnly = this.isHexOnly; + object.valueHex = (0, _pvutils.bufferToHexCodes)(this.valueHex, 0, this.valueHex.byteLength); + + return object; + } + //********************************************************************************** +} +//************************************************************************************** +class BitString extends BaseBlock { + //********************************************************************************** + /** + * Constructor for "BitString" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) { + super(parameters, LocalBitStringValueBlock); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 3; // BitString + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "BitString"; + } + //********************************************************************************** + /** + * Base function for converting block from BER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {number} Offset after least decoded byte + */ + fromBER(inputBuffer, inputOffset, inputLength) { + //region Ability to encode empty BitString + if (inputLength === 0) return inputOffset; + //endregion + + this.valueBlock.isConstructed = this.idBlock.isConstructed; + this.valueBlock.isIndefiniteForm = this.lenBlock.isIndefiniteForm; + + return super.fromBER(inputBuffer, inputOffset, inputLength); + } + //********************************************************************************** + /** + * Checking that two BITSTRINGs are equal + * @param {BitString} bitString + */ + isEqual(bitString) { + //region Check input type + if (bitString instanceof BitString === false) return false; + //endregion + + //region Compare two JSON strings + if (JSON.stringify(this) !== JSON.stringify(bitString)) return false; + //endregion + + return true; + } + //********************************************************************************** +} +exports.BitString = BitString; //************************************************************************************** +//endregion +//************************************************************************************** +//region Declaration of ASN.1 Integer type class +//************************************************************************************** +/** + * @extends LocalValueBlock + */ + +class LocalIntegerValueBlock extends LocalHexBlock(LocalValueBlock) { + //********************************************************************************** + /** + * Constructor for "LocalIntegerValueBlock" class + * @param {Object} [parameters={}] + * @property {ArrayBuffer} [valueHex] + */ + constructor(parameters = {}) { + super(parameters); + + if ("value" in parameters) this.valueDec = parameters.value; + } + //********************************************************************************** + /** + * Setter for "valueHex" + * @param {ArrayBuffer} _value + */ + set valueHex(_value) { + this._valueHex = _value.slice(0); + + if (_value.byteLength >= 4) { + this.warnings.push("Too big Integer for decoding, hex only"); + this.isHexOnly = true; + this._valueDec = 0; + } else { + this.isHexOnly = false; + + if (_value.byteLength > 0) this._valueDec = _pvutils.utilDecodeTC.call(this); + } + } + //********************************************************************************** + /** + * Getter for "valueHex" + * @returns {ArrayBuffer} + */ + get valueHex() { + return this._valueHex; + } + //********************************************************************************** + /** + * Getter for "valueDec" + * @param {number} _value + */ + set valueDec(_value) { + this._valueDec = _value; + + this.isHexOnly = false; + this._valueHex = (0, _pvutils.utilEncodeTC)(_value); + } + //********************************************************************************** + /** + * Getter for "valueDec" + * @returns {number} + */ + get valueDec() { + return this._valueDec; + } + //********************************************************************************** + /** + * Base function for converting block from DER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 DER encoded array + * @param {!number} inputOffset Offset in ASN.1 DER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @param {number} [expectedLength=0] Expected length of converted "valueHex" buffer + * @returns {number} Offset after least decoded byte + */ + fromDER(inputBuffer, inputOffset, inputLength, expectedLength = 0) { + const offset = this.fromBER(inputBuffer, inputOffset, inputLength); + if (offset === -1) return offset; + + const view = new Uint8Array(this._valueHex); + + if (view[0] === 0x00 && (view[1] & 0x80) !== 0) { + const updatedValueHex = new ArrayBuffer(this._valueHex.byteLength - 1); + const updatedView = new Uint8Array(updatedValueHex); + + updatedView.set(new Uint8Array(this._valueHex, 1, this._valueHex.byteLength - 1)); + + this._valueHex = updatedValueHex.slice(0); + } else { + if (expectedLength !== 0) { + if (this._valueHex.byteLength < expectedLength) { + if (expectedLength - this._valueHex.byteLength > 1) expectedLength = this._valueHex.byteLength + 1; + + const updatedValueHex = new ArrayBuffer(expectedLength); + const updatedView = new Uint8Array(updatedValueHex); + + updatedView.set(view, expectedLength - this._valueHex.byteLength); + + this._valueHex = updatedValueHex.slice(0); + } + } + } + + return offset; + } + //********************************************************************************** + /** + * Encoding of current ASN.1 block into ASN.1 encoded array (DER rules) + * @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes + * @returns {ArrayBuffer} + */ + toDER(sizeOnly = false) { + const view = new Uint8Array(this._valueHex); + + switch (true) { + case (view[0] & 0x80) !== 0: + { + const updatedValueHex = new ArrayBuffer(this._valueHex.byteLength + 1); + const updatedView = new Uint8Array(updatedValueHex); + + updatedView[0] = 0x00; + updatedView.set(view, 1); + + this._valueHex = updatedValueHex.slice(0); + } + break; + case view[0] === 0x00 && (view[1] & 0x80) === 0: + { + const updatedValueHex = new ArrayBuffer(this._valueHex.byteLength - 1); + const updatedView = new Uint8Array(updatedValueHex); + + updatedView.set(new Uint8Array(this._valueHex, 1, this._valueHex.byteLength - 1)); + + this._valueHex = updatedValueHex.slice(0); + } + break; + default: + } + + return this.toBER(sizeOnly); + } + //********************************************************************************** + /** + * Base function for converting block from BER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {number} Offset after least decoded byte + */ + fromBER(inputBuffer, inputOffset, inputLength) { + const resultOffset = super.fromBER(inputBuffer, inputOffset, inputLength); + if (resultOffset === -1) return resultOffset; + + this.blockLength = inputLength; + + return inputOffset + inputLength; + } + //********************************************************************************** + /** + * Encoding of current ASN.1 block into ASN.1 encoded array (BER rules) + * @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes + * @returns {ArrayBuffer} + */ + toBER(sizeOnly = false) { + //noinspection JSCheckFunctionSignatures + return this.valueHex.slice(0); + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "IntegerValueBlock"; + } + //********************************************************************************** + //noinspection JSUnusedGlobalSymbols + /** + * Convertion for the block to JSON object + * @returns {Object} + */ + toJSON() { + let object = {}; + + //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object + try { + object = super.toJSON(); + } catch (ex) {} + //endregion + + object.valueDec = this.valueDec; + + return object; + } + //********************************************************************************** + /** + * Convert current value to decimal string representation + */ + toString() { + //region Aux functions + function viewAdd(first, second) { + //region Initial variables + const c = new Uint8Array([0]); + + let firstView = new Uint8Array(first); + let secondView = new Uint8Array(second); + + let firstViewCopy = firstView.slice(0); + const firstViewCopyLength = firstViewCopy.length - 1; + let secondViewCopy = secondView.slice(0); + const secondViewCopyLength = secondViewCopy.length - 1; + + let value = 0; + + const max = secondViewCopyLength < firstViewCopyLength ? firstViewCopyLength : secondViewCopyLength; + + let counter = 0; + //endregion + + for (let i = max; i >= 0; i--, counter++) { + switch (true) { + case counter < secondViewCopy.length: + value = firstViewCopy[firstViewCopyLength - counter] + secondViewCopy[secondViewCopyLength - counter] + c[0]; + break; + default: + value = firstViewCopy[firstViewCopyLength - counter] + c[0]; + } + + c[0] = value / 10; + + switch (true) { + case counter >= firstViewCopy.length: + firstViewCopy = (0, _pvutils.utilConcatView)(new Uint8Array([value % 10]), firstViewCopy); + break; + default: + firstViewCopy[firstViewCopyLength - counter] = value % 10; + } + } + + if (c[0] > 0) firstViewCopy = (0, _pvutils.utilConcatView)(c, firstViewCopy); + + return firstViewCopy.slice(0); + } + + function power2(n) { + if (n >= powers2.length) { + for (let p = powers2.length; p <= n; p++) { + const c = new Uint8Array([0]); + let digits = powers2[p - 1].slice(0); + + for (let i = digits.length - 1; i >= 0; i--) { + const newValue = new Uint8Array([(digits[i] << 1) + c[0]]); + c[0] = newValue[0] / 10; + digits[i] = newValue[0] % 10; + } + + if (c[0] > 0) digits = (0, _pvutils.utilConcatView)(c, digits); + + powers2.push(digits); + } + } + + return powers2[n]; + } + + function viewSub(first, second) { + //region Initial variables + let b = 0; + + let firstView = new Uint8Array(first); + let secondView = new Uint8Array(second); + + let firstViewCopy = firstView.slice(0); + const firstViewCopyLength = firstViewCopy.length - 1; + let secondViewCopy = secondView.slice(0); + const secondViewCopyLength = secondViewCopy.length - 1; + + let value; + + let counter = 0; + //endregion + + for (let i = secondViewCopyLength; i >= 0; i--, counter++) { + value = firstViewCopy[firstViewCopyLength - counter] - secondViewCopy[secondViewCopyLength - counter] - b; + + switch (true) { + case value < 0: + b = 1; + firstViewCopy[firstViewCopyLength - counter] = value + 10; + break; + default: + b = 0; + firstViewCopy[firstViewCopyLength - counter] = value; + } + } + + if (b > 0) { + for (let i = firstViewCopyLength - secondViewCopyLength + 1; i >= 0; i--, counter++) { + value = firstViewCopy[firstViewCopyLength - counter] - b; + + if (value < 0) { + b = 1; + firstViewCopy[firstViewCopyLength - counter] = value + 10; + } else { + b = 0; + firstViewCopy[firstViewCopyLength - counter] = value; + break; + } + } + } + + return firstViewCopy.slice(); + } + //endregion + + //region Initial variables + const firstBit = this._valueHex.byteLength * 8 - 1; + + let digits = new Uint8Array(this._valueHex.byteLength * 8 / 3); + let bitNumber = 0; + let currentByte; + + const asn1View = new Uint8Array(this._valueHex); + + let result = ""; + + let flag = false; + //endregion + + //region Calculate number + for (let byteNumber = this._valueHex.byteLength - 1; byteNumber >= 0; byteNumber--) { + currentByte = asn1View[byteNumber]; + + for (let i = 0; i < 8; i++) { + if ((currentByte & 1) === 1) { + switch (bitNumber) { + case firstBit: + digits = viewSub(power2(bitNumber), digits); + result = "-"; + break; + default: + digits = viewAdd(digits, power2(bitNumber)); + } + } + + bitNumber++; + currentByte >>= 1; + } + } + //endregion + + //region Print number + for (let i = 0; i < digits.length; i++) { + if (digits[i]) flag = true; + + if (flag) result += digitsString.charAt(digits[i]); + } + + if (flag === false) result += digitsString.charAt(0); + //endregion + + return result; + } + //********************************************************************************** +} +//************************************************************************************** +class Integer extends BaseBlock { + //********************************************************************************** + /** + * Constructor for "Integer" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) { + super(parameters, LocalIntegerValueBlock); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 2; // Integer + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "Integer"; + } + //********************************************************************************** + //noinspection JSUnusedGlobalSymbols + /** + * Compare two Integer object, or Integer and ArrayBuffer objects + * @param {!Integer|ArrayBuffer} otherValue + * @returns {boolean} + */ + isEqual(otherValue) { + if (otherValue instanceof Integer) { + if (this.valueBlock.isHexOnly && otherValue.valueBlock.isHexOnly) // Compare two ArrayBuffers + return (0, _pvutils.isEqualBuffer)(this.valueBlock.valueHex, otherValue.valueBlock.valueHex); + + if (this.valueBlock.isHexOnly === otherValue.valueBlock.isHexOnly) return this.valueBlock.valueDec === otherValue.valueBlock.valueDec; + + return false; + } + + if (otherValue instanceof ArrayBuffer) return (0, _pvutils.isEqualBuffer)(this.valueBlock.valueHex, otherValue); + + return false; + } + //********************************************************************************** + /** + * Convert current Integer value from BER into DER format + * @returns {Integer} + */ + convertToDER() { + const integer = new Integer({ valueHex: this.valueBlock.valueHex }); + integer.valueBlock.toDER(); + + return integer; + } + //********************************************************************************** + /** + * Convert current Integer value from DER to BER format + * @returns {Integer} + */ + convertFromDER() { + const expectedLength = this.valueBlock.valueHex.byteLength % 2 ? this.valueBlock.valueHex.byteLength + 1 : this.valueBlock.valueHex.byteLength; + const integer = new Integer({ valueHex: this.valueBlock.valueHex }); + integer.valueBlock.fromDER(integer.valueBlock.valueHex, 0, integer.valueBlock.valueHex.byteLength, expectedLength); + + return integer; + } + //********************************************************************************** +} +exports.Integer = Integer; //************************************************************************************** +//endregion +//************************************************************************************** +//region Declaration of ASN.1 Enumerated type class +//************************************************************************************** + +class Enumerated extends Integer { + //********************************************************************************** + /** + * Constructor for "Enumerated" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) { + super(parameters); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 10; // Enumerated + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "Enumerated"; + } + //********************************************************************************** +} +exports.Enumerated = Enumerated; //************************************************************************************** +//endregion +//************************************************************************************** +//region Declaration of ASN.1 ObjectIdentifier type class +//************************************************************************************** + +class LocalSidValueBlock extends LocalHexBlock(LocalBaseBlock) { + //********************************************************************************** + /** + * Constructor for "LocalSidValueBlock" class + * @param {Object} [parameters={}] + * @property {number} [valueDec] + * @property {boolean} [isFirstSid] + */ + constructor(parameters = {}) { + super(parameters); + + this.valueDec = (0, _pvutils.getParametersValue)(parameters, "valueDec", -1); + this.isFirstSid = (0, _pvutils.getParametersValue)(parameters, "isFirstSid", false); + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "sidBlock"; + } + //********************************************************************************** + /** + * Base function for converting block from BER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {number} Offset after least decoded byte + */ + fromBER(inputBuffer, inputOffset, inputLength) { + if (inputLength === 0) return inputOffset; + + //region Basic check for parameters + //noinspection JSCheckFunctionSignatures + if ((0, _pvutils.checkBufferParams)(this, inputBuffer, inputOffset, inputLength) === false) return -1; + //endregion + + const intBuffer = new Uint8Array(inputBuffer, inputOffset, inputLength); + + this.valueHex = new ArrayBuffer(inputLength); + let view = new Uint8Array(this.valueHex); + + for (let i = 0; i < inputLength; i++) { + view[i] = intBuffer[i] & 0x7F; + + this.blockLength++; + + if ((intBuffer[i] & 0x80) === 0x00) break; + } + + //region Ajust size of valueHex buffer + const tempValueHex = new ArrayBuffer(this.blockLength); + const tempView = new Uint8Array(tempValueHex); + + for (let i = 0; i < this.blockLength; i++) tempView[i] = view[i]; + + //noinspection JSCheckFunctionSignatures + this.valueHex = tempValueHex.slice(0); + view = new Uint8Array(this.valueHex); + //endregion + + if ((intBuffer[this.blockLength - 1] & 0x80) !== 0x00) { + this.error = "End of input reached before message was fully decoded"; + return -1; + } + + if (view[0] === 0x00) this.warnings.push("Needlessly long format of SID encoding"); + + if (this.blockLength <= 8) this.valueDec = (0, _pvutils.utilFromBase)(view, 7);else { + this.isHexOnly = true; + this.warnings.push("Too big SID for decoding, hex only"); + } + + return inputOffset + this.blockLength; + } + //********************************************************************************** + /** + * Encoding of current ASN.1 block into ASN.1 encoded array (BER rules) + * @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes + * @returns {ArrayBuffer} + */ + toBER(sizeOnly = false) { + //region Initial variables + let retBuf; + let retView; + //endregion + + if (this.isHexOnly) { + if (sizeOnly === true) return new ArrayBuffer(this.valueHex.byteLength); + + const curView = new Uint8Array(this.valueHex); + + retBuf = new ArrayBuffer(this.blockLength); + retView = new Uint8Array(retBuf); + + for (let i = 0; i < this.blockLength - 1; i++) retView[i] = curView[i] | 0x80; + + retView[this.blockLength - 1] = curView[this.blockLength - 1]; + + return retBuf; + } + + const encodedBuf = (0, _pvutils.utilToBase)(this.valueDec, 7); + if (encodedBuf.byteLength === 0) { + this.error = "Error during encoding SID value"; + return new ArrayBuffer(0); + } + + retBuf = new ArrayBuffer(encodedBuf.byteLength); + + if (sizeOnly === false) { + const encodedView = new Uint8Array(encodedBuf); + retView = new Uint8Array(retBuf); + + for (let i = 0; i < encodedBuf.byteLength - 1; i++) retView[i] = encodedView[i] | 0x80; + + retView[encodedBuf.byteLength - 1] = encodedView[encodedBuf.byteLength - 1]; + } + + return retBuf; + } + //********************************************************************************** + /** + * Create string representation of current SID block + * @returns {string} + */ + toString() { + let result = ""; + + if (this.isHexOnly === true) result = (0, _pvutils.bufferToHexCodes)(this.valueHex, 0, this.valueHex.byteLength);else { + if (this.isFirstSid) { + let sidValue = this.valueDec; + + if (this.valueDec <= 39) result = "0.";else { + if (this.valueDec <= 79) { + result = "1."; + sidValue -= 40; + } else { + result = "2."; + sidValue -= 80; + } + } + + result += sidValue.toString(); + } else result = this.valueDec.toString(); + } + + return result; + } + //********************************************************************************** + //noinspection JSUnusedGlobalSymbols + /** + * Convertion for the block to JSON object + * @returns {Object} + */ + toJSON() { + let object = {}; + + //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object + try { + object = super.toJSON(); + } catch (ex) {} + //endregion + + object.valueDec = this.valueDec; + object.isFirstSid = this.isFirstSid; + + return object; + } + //********************************************************************************** +} +//************************************************************************************** +class LocalObjectIdentifierValueBlock extends LocalValueBlock { + //********************************************************************************** + /** + * Constructor for "LocalObjectIdentifierValueBlock" class + * @param {Object} [parameters={}] + * @property {ArrayBuffer} [valueHex] + */ + constructor(parameters = {}) { + super(parameters); + + this.fromString((0, _pvutils.getParametersValue)(parameters, "value", "")); + } + //********************************************************************************** + /** + * Base function for converting block from BER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {number} Offset after least decoded byte + */ + fromBER(inputBuffer, inputOffset, inputLength) { + let resultOffset = inputOffset; + + while (inputLength > 0) { + const sidBlock = new LocalSidValueBlock(); + resultOffset = sidBlock.fromBER(inputBuffer, resultOffset, inputLength); + if (resultOffset === -1) { + this.blockLength = 0; + this.error = sidBlock.error; + return resultOffset; + } + + if (this.value.length === 0) sidBlock.isFirstSid = true; + + this.blockLength += sidBlock.blockLength; + inputLength -= sidBlock.blockLength; + + this.value.push(sidBlock); + } + + return resultOffset; + } + //********************************************************************************** + /** + * Encoding of current ASN.1 block into ASN.1 encoded array (BER rules) + * @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes + * @returns {ArrayBuffer} + */ + toBER(sizeOnly = false) { + let retBuf = new ArrayBuffer(0); + + for (let i = 0; i < this.value.length; i++) { + const valueBuf = this.value[i].toBER(sizeOnly); + if (valueBuf.byteLength === 0) { + this.error = this.value[i].error; + return new ArrayBuffer(0); + } + + retBuf = (0, _pvutils.utilConcatBuf)(retBuf, valueBuf); + } + + return retBuf; + } + //********************************************************************************** + /** + * Create "LocalObjectIdentifierValueBlock" class from string + * @param {string} string Input string to convert from + * @returns {boolean} + */ + fromString(string) { + this.value = []; // Clear existing SID values + + let pos1 = 0; + let pos2 = 0; + + let sid = ""; + + let flag = false; + + do { + pos2 = string.indexOf(".", pos1); + if (pos2 === -1) sid = string.substr(pos1);else sid = string.substr(pos1, pos2 - pos1); + + pos1 = pos2 + 1; + + if (flag) { + const sidBlock = this.value[0]; + + let plus = 0; + + switch (sidBlock.valueDec) { + case 0: + break; + case 1: + plus = 40; + break; + case 2: + plus = 80; + break; + default: + this.value = []; // clear SID array + return false; // ??? + } + + const parsedSID = parseInt(sid, 10); + if (isNaN(parsedSID)) return true; + + sidBlock.valueDec = parsedSID + plus; + + flag = false; + } else { + const sidBlock = new LocalSidValueBlock(); + sidBlock.valueDec = parseInt(sid, 10); + if (isNaN(sidBlock.valueDec)) return true; + + if (this.value.length === 0) { + sidBlock.isFirstSid = true; + flag = true; + } + + this.value.push(sidBlock); + } + } while (pos2 !== -1); + + return true; + } + //********************************************************************************** + /** + * Converts "LocalObjectIdentifierValueBlock" class to string + * @returns {string} + */ + toString() { + let result = ""; + let isHexOnly = false; + + for (let i = 0; i < this.value.length; i++) { + isHexOnly = this.value[i].isHexOnly; + + let sidStr = this.value[i].toString(); + + if (i !== 0) result = `${result}.`; + + if (isHexOnly) { + sidStr = `{${sidStr}}`; + + if (this.value[i].isFirstSid) result = `2.{${sidStr} - 80}`;else result += sidStr; + } else result += sidStr; + } + + return result; + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "ObjectIdentifierValueBlock"; + } + //********************************************************************************** + /** + * Convertion for the block to JSON object + * @returns {Object} + */ + toJSON() { + let object = {}; + + //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object + try { + object = super.toJSON(); + } catch (ex) {} + //endregion + + object.value = this.toString(); + object.sidArray = []; + for (let i = 0; i < this.value.length; i++) object.sidArray.push(this.value[i].toJSON()); + + return object; + } + //********************************************************************************** +} +//************************************************************************************** +/** + * @extends BaseBlock + */ +class ObjectIdentifier extends BaseBlock { + //********************************************************************************** + /** + * Constructor for "ObjectIdentifier" class + * @param {Object} [parameters={}] + * @property {ArrayBuffer} [valueHex] + */ + constructor(parameters = {}) { + super(parameters, LocalObjectIdentifierValueBlock); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 6; // OBJECT IDENTIFIER + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "ObjectIdentifier"; + } + //********************************************************************************** +} +exports.ObjectIdentifier = ObjectIdentifier; //************************************************************************************** +//endregion +//************************************************************************************** +//region Declaration of all string's classes +//************************************************************************************** + +class LocalUtf8StringValueBlock extends LocalHexBlock(LocalBaseBlock) { + //********************************************************************************** + //noinspection JSUnusedGlobalSymbols + /** + * Constructor for "LocalUtf8StringValueBlock" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) { + super(parameters); + + this.isHexOnly = true; + this.value = ""; // String representation of decoded ArrayBuffer + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "Utf8StringValueBlock"; + } + //********************************************************************************** + //noinspection JSUnusedGlobalSymbols + /** + * Convertion for the block to JSON object + * @returns {Object} + */ + toJSON() { + let object = {}; + + //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object + try { + object = super.toJSON(); + } catch (ex) {} + //endregion + + object.value = this.value; + + return object; + } + //********************************************************************************** +} +//************************************************************************************** +/** + * @extends BaseBlock + */ +class Utf8String extends BaseBlock { + //********************************************************************************** + /** + * Constructor for "Utf8String" class + * @param {Object} [parameters={}] + * @property {ArrayBuffer} [valueHex] + */ + constructor(parameters = {}) { + super(parameters, LocalUtf8StringValueBlock); + + if ("value" in parameters) this.fromString(parameters.value); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 12; // Utf8String + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "Utf8String"; + } + //********************************************************************************** + /** + * Base function for converting block from BER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {number} Offset after least decoded byte + */ + fromBER(inputBuffer, inputOffset, inputLength) { + const resultOffset = this.valueBlock.fromBER(inputBuffer, inputOffset, this.lenBlock.isIndefiniteForm === true ? inputLength : this.lenBlock.length); + if (resultOffset === -1) { + this.error = this.valueBlock.error; + return resultOffset; + } + + this.fromBuffer(this.valueBlock.valueHex); + + if (this.idBlock.error.length === 0) this.blockLength += this.idBlock.blockLength; + + if (this.lenBlock.error.length === 0) this.blockLength += this.lenBlock.blockLength; + + if (this.valueBlock.error.length === 0) this.blockLength += this.valueBlock.blockLength; + + return resultOffset; + } + //********************************************************************************** + /** + * Function converting ArrayBuffer into ASN.1 internal string + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + */ + fromBuffer(inputBuffer) { + this.valueBlock.value = String.fromCharCode.apply(null, new Uint8Array(inputBuffer)); + + try { + //noinspection JSDeprecatedSymbols + this.valueBlock.value = decodeURIComponent(escape(this.valueBlock.value)); + } catch (ex) { + this.warnings.push(`Error during "decodeURIComponent": ${ex}, using raw string`); + } + } + //********************************************************************************** + /** + * Function converting JavaScript string into ASN.1 internal class + * @param {!string} inputString ASN.1 BER encoded array + */ + fromString(inputString) { + //noinspection JSDeprecatedSymbols + const str = unescape(encodeURIComponent(inputString)); + const strLen = str.length; + + this.valueBlock.valueHex = new ArrayBuffer(strLen); + const view = new Uint8Array(this.valueBlock.valueHex); + + for (let i = 0; i < strLen; i++) view[i] = str.charCodeAt(i); + + this.valueBlock.value = inputString; + } + //********************************************************************************** +} +exports.Utf8String = Utf8String; //************************************************************************************** +/** + * @extends LocalBaseBlock + * @extends LocalHexBlock + */ + +class LocalBmpStringValueBlock extends LocalHexBlock(LocalBaseBlock) { + //********************************************************************************** + /** + * Constructor for "LocalBmpStringValueBlock" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) { + super(parameters); + + this.isHexOnly = true; + this.value = ""; + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "BmpStringValueBlock"; + } + //********************************************************************************** + //noinspection JSUnusedGlobalSymbols + /** + * Convertion for the block to JSON object + * @returns {Object} + */ + toJSON() { + let object = {}; + + //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object + try { + object = super.toJSON(); + } catch (ex) {} + //endregion + + object.value = this.value; + + return object; + } + //********************************************************************************** +} +//************************************************************************************** +/** + * @extends BaseBlock + */ +class BmpString extends BaseBlock { + //********************************************************************************** + /** + * Constructor for "BmpString" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) { + super(parameters, LocalBmpStringValueBlock); + + if ("value" in parameters) this.fromString(parameters.value); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 30; // BmpString + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "BmpString"; + } + //********************************************************************************** + /** + * Base function for converting block from BER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {number} Offset after least decoded byte + */ + fromBER(inputBuffer, inputOffset, inputLength) { + const resultOffset = this.valueBlock.fromBER(inputBuffer, inputOffset, this.lenBlock.isIndefiniteForm === true ? inputLength : this.lenBlock.length); + if (resultOffset === -1) { + this.error = this.valueBlock.error; + return resultOffset; + } + + this.fromBuffer(this.valueBlock.valueHex); + + if (this.idBlock.error.length === 0) this.blockLength += this.idBlock.blockLength; + + if (this.lenBlock.error.length === 0) this.blockLength += this.lenBlock.blockLength; + + if (this.valueBlock.error.length === 0) this.blockLength += this.valueBlock.blockLength; + + return resultOffset; + } + //********************************************************************************** + /** + * Function converting ArrayBuffer into ASN.1 internal string + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + */ + fromBuffer(inputBuffer) { + //noinspection JSCheckFunctionSignatures + const copyBuffer = inputBuffer.slice(0); + const valueView = new Uint8Array(copyBuffer); + + for (let i = 0; i < valueView.length; i += 2) { + const temp = valueView[i]; + + valueView[i] = valueView[i + 1]; + valueView[i + 1] = temp; + } + + this.valueBlock.value = String.fromCharCode.apply(null, new Uint16Array(copyBuffer)); + } + //********************************************************************************** + /** + * Function converting JavaScript string into ASN.1 internal class + * @param {!string} inputString ASN.1 BER encoded array + */ + fromString(inputString) { + const strLength = inputString.length; + + this.valueBlock.valueHex = new ArrayBuffer(strLength * 2); + const valueHexView = new Uint8Array(this.valueBlock.valueHex); + + for (let i = 0; i < strLength; i++) { + const codeBuf = (0, _pvutils.utilToBase)(inputString.charCodeAt(i), 8); + const codeView = new Uint8Array(codeBuf); + if (codeView.length > 2) continue; + + const dif = 2 - codeView.length; + + for (let j = codeView.length - 1; j >= 0; j--) valueHexView[i * 2 + j + dif] = codeView[j]; + } + + this.valueBlock.value = inputString; + } + //********************************************************************************** +} +exports.BmpString = BmpString; //************************************************************************************** + +class LocalUniversalStringValueBlock extends LocalHexBlock(LocalBaseBlock) { + //********************************************************************************** + /** + * Constructor for "LocalUniversalStringValueBlock" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) { + super(parameters); + + this.isHexOnly = true; + this.value = ""; + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "UniversalStringValueBlock"; + } + //********************************************************************************** + //noinspection JSUnusedGlobalSymbols + /** + * Convertion for the block to JSON object + * @returns {Object} + */ + toJSON() { + let object = {}; + + //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object + try { + object = super.toJSON(); + } catch (ex) {} + //endregion + + object.value = this.value; + + return object; + } + //********************************************************************************** +} +//************************************************************************************** +/** + * @extends BaseBlock + */ +class UniversalString extends BaseBlock { + //********************************************************************************** + /** + * Constructor for "UniversalString" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) { + super(parameters, LocalUniversalStringValueBlock); + + if ("value" in parameters) this.fromString(parameters.value); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 28; // UniversalString + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "UniversalString"; + } + //********************************************************************************** + /** + * Base function for converting block from BER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {number} Offset after least decoded byte + */ + fromBER(inputBuffer, inputOffset, inputLength) { + const resultOffset = this.valueBlock.fromBER(inputBuffer, inputOffset, this.lenBlock.isIndefiniteForm === true ? inputLength : this.lenBlock.length); + if (resultOffset === -1) { + this.error = this.valueBlock.error; + return resultOffset; + } + + this.fromBuffer(this.valueBlock.valueHex); + + if (this.idBlock.error.length === 0) this.blockLength += this.idBlock.blockLength; + + if (this.lenBlock.error.length === 0) this.blockLength += this.lenBlock.blockLength; + + if (this.valueBlock.error.length === 0) this.blockLength += this.valueBlock.blockLength; + + return resultOffset; + } + //********************************************************************************** + /** + * Function converting ArrayBuffer into ASN.1 internal string + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + */ + fromBuffer(inputBuffer) { + //noinspection JSCheckFunctionSignatures + const copyBuffer = inputBuffer.slice(0); + const valueView = new Uint8Array(copyBuffer); + + for (let i = 0; i < valueView.length; i += 4) { + valueView[i] = valueView[i + 3]; + valueView[i + 1] = valueView[i + 2]; + valueView[i + 2] = 0x00; + valueView[i + 3] = 0x00; + } + + this.valueBlock.value = String.fromCharCode.apply(null, new Uint32Array(copyBuffer)); + } + //********************************************************************************** + /** + * Function converting JavaScript string into ASN.1 internal class + * @param {!string} inputString ASN.1 BER encoded array + */ + fromString(inputString) { + const strLength = inputString.length; + + this.valueBlock.valueHex = new ArrayBuffer(strLength * 4); + const valueHexView = new Uint8Array(this.valueBlock.valueHex); + + for (let i = 0; i < strLength; i++) { + const codeBuf = (0, _pvutils.utilToBase)(inputString.charCodeAt(i), 8); + const codeView = new Uint8Array(codeBuf); + if (codeView.length > 4) continue; + + const dif = 4 - codeView.length; + + for (let j = codeView.length - 1; j >= 0; j--) valueHexView[i * 4 + j + dif] = codeView[j]; + } + + this.valueBlock.value = inputString; + } + //********************************************************************************** +} +exports.UniversalString = UniversalString; //************************************************************************************** + +class LocalSimpleStringValueBlock extends LocalHexBlock(LocalBaseBlock) { + //********************************************************************************** + /** + * Constructor for "LocalSimpleStringValueBlock" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) { + super(parameters); + + this.value = ""; + this.isHexOnly = true; + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "SimpleStringValueBlock"; + } + //********************************************************************************** + //noinspection JSUnusedGlobalSymbols + /** + * Convertion for the block to JSON object + * @returns {Object} + */ + toJSON() { + let object = {}; + + //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object + try { + object = super.toJSON(); + } catch (ex) {} + //endregion + + object.value = this.value; + + return object; + } + //********************************************************************************** +} +//************************************************************************************** +/** + * @extends BaseBlock + */ +class LocalSimpleStringBlock extends BaseBlock { + //********************************************************************************** + /** + * Constructor for "LocalSimpleStringBlock" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) { + super(parameters, LocalSimpleStringValueBlock); + + if ("value" in parameters) this.fromString(parameters.value); + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "SIMPLESTRING"; + } + //********************************************************************************** + /** + * Base function for converting block from BER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {number} Offset after least decoded byte + */ + fromBER(inputBuffer, inputOffset, inputLength) { + const resultOffset = this.valueBlock.fromBER(inputBuffer, inputOffset, this.lenBlock.isIndefiniteForm === true ? inputLength : this.lenBlock.length); + if (resultOffset === -1) { + this.error = this.valueBlock.error; + return resultOffset; + } + + this.fromBuffer(this.valueBlock.valueHex); + + if (this.idBlock.error.length === 0) this.blockLength += this.idBlock.blockLength; + + if (this.lenBlock.error.length === 0) this.blockLength += this.lenBlock.blockLength; + + if (this.valueBlock.error.length === 0) this.blockLength += this.valueBlock.blockLength; + + return resultOffset; + } + //********************************************************************************** + /** + * Function converting ArrayBuffer into ASN.1 internal string + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + */ + fromBuffer(inputBuffer) { + this.valueBlock.value = String.fromCharCode.apply(null, new Uint8Array(inputBuffer)); + } + //********************************************************************************** + /** + * Function converting JavaScript string into ASN.1 internal class + * @param {!string} inputString ASN.1 BER encoded array + */ + fromString(inputString) { + const strLen = inputString.length; + + this.valueBlock.valueHex = new ArrayBuffer(strLen); + const view = new Uint8Array(this.valueBlock.valueHex); + + for (let i = 0; i < strLen; i++) view[i] = inputString.charCodeAt(i); + + this.valueBlock.value = inputString; + } + //********************************************************************************** +} +//************************************************************************************** +/** + * @extends LocalSimpleStringBlock + */ +class NumericString extends LocalSimpleStringBlock { + //********************************************************************************** + /** + * Constructor for "NumericString" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) { + super(parameters); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 18; // NumericString + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "NumericString"; + } + //********************************************************************************** +} +exports.NumericString = NumericString; //************************************************************************************** +/** + * @extends LocalSimpleStringBlock + */ + +class PrintableString extends LocalSimpleStringBlock { + //********************************************************************************** + /** + * Constructor for "PrintableString" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) { + super(parameters); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 19; // PrintableString + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "PrintableString"; + } + //********************************************************************************** +} +exports.PrintableString = PrintableString; //************************************************************************************** +/** + * @extends LocalSimpleStringBlock + */ + +class TeletexString extends LocalSimpleStringBlock { + //********************************************************************************** + /** + * Constructor for "TeletexString" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) { + super(parameters); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 20; // TeletexString + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "TeletexString"; + } + //********************************************************************************** +} +exports.TeletexString = TeletexString; //************************************************************************************** +/** + * @extends LocalSimpleStringBlock + */ + +class VideotexString extends LocalSimpleStringBlock { + //********************************************************************************** + /** + * Constructor for "VideotexString" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) { + super(parameters); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 21; // VideotexString + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "VideotexString"; + } + //********************************************************************************** +} +exports.VideotexString = VideotexString; //************************************************************************************** +/** + * @extends LocalSimpleStringBlock + */ + +class IA5String extends LocalSimpleStringBlock { + //********************************************************************************** + /** + * Constructor for "IA5String" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) { + super(parameters); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 22; // IA5String + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "IA5String"; + } + //********************************************************************************** +} +exports.IA5String = IA5String; //************************************************************************************** +/** + * @extends LocalSimpleStringBlock + */ + +class GraphicString extends LocalSimpleStringBlock { + //********************************************************************************** + /** + * Constructor for "GraphicString" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) { + super(parameters); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 25; // GraphicString + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "GraphicString"; + } + //********************************************************************************** +} +exports.GraphicString = GraphicString; //************************************************************************************** +/** + * @extends LocalSimpleStringBlock + */ + +class VisibleString extends LocalSimpleStringBlock { + //********************************************************************************** + /** + * Constructor for "VisibleString" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) { + super(parameters); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 26; // VisibleString + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "VisibleString"; + } + //********************************************************************************** +} +exports.VisibleString = VisibleString; //************************************************************************************** +/** + * @extends LocalSimpleStringBlock + */ + +class GeneralString extends LocalSimpleStringBlock { + //********************************************************************************** + /** + * Constructor for "GeneralString" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) { + super(parameters); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 27; // GeneralString + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "GeneralString"; + } + //********************************************************************************** +} +exports.GeneralString = GeneralString; //************************************************************************************** +/** + * @extends LocalSimpleStringBlock + */ + +class CharacterString extends LocalSimpleStringBlock { + //********************************************************************************** + /** + * Constructor for "CharacterString" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) { + super(parameters); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 29; // CharacterString + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "CharacterString"; + } + //********************************************************************************** +} +exports.CharacterString = CharacterString; //************************************************************************************** +//endregion +//************************************************************************************** +//region Declaration of all date and time classes +//************************************************************************************** +/** + * @extends VisibleString + */ + +class UTCTime extends VisibleString { + //********************************************************************************** + /** + * Constructor for "UTCTime" class + * @param {Object} [parameters={}] + * @property {string} [value] String representatio of the date + * @property {Date} [valueDate] JavaScript "Date" object + */ + constructor(parameters = {}) { + super(parameters); + + this.year = 0; + this.month = 0; + this.day = 0; + this.hour = 0; + this.minute = 0; + this.second = 0; + + //region Create UTCTime from ASN.1 UTC string value + if ("value" in parameters) { + this.fromString(parameters.value); + + this.valueBlock.valueHex = new ArrayBuffer(parameters.value.length); + const view = new Uint8Array(this.valueBlock.valueHex); + + for (let i = 0; i < parameters.value.length; i++) view[i] = parameters.value.charCodeAt(i); + } + //endregion + //region Create GeneralizedTime from JavaScript Date type + if ("valueDate" in parameters) { + this.fromDate(parameters.valueDate); + this.valueBlock.valueHex = this.toBuffer(); + } + //endregion + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 23; // UTCTime + } + //********************************************************************************** + /** + * Base function for converting block from BER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {number} Offset after least decoded byte + */ + fromBER(inputBuffer, inputOffset, inputLength) { + const resultOffset = this.valueBlock.fromBER(inputBuffer, inputOffset, this.lenBlock.isIndefiniteForm === true ? inputLength : this.lenBlock.length); + if (resultOffset === -1) { + this.error = this.valueBlock.error; + return resultOffset; + } + + this.fromBuffer(this.valueBlock.valueHex); + + if (this.idBlock.error.length === 0) this.blockLength += this.idBlock.blockLength; + + if (this.lenBlock.error.length === 0) this.blockLength += this.lenBlock.blockLength; + + if (this.valueBlock.error.length === 0) this.blockLength += this.valueBlock.blockLength; + + return resultOffset; + } + //********************************************************************************** + /** + * Function converting ArrayBuffer into ASN.1 internal string + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + */ + fromBuffer(inputBuffer) { + this.fromString(String.fromCharCode.apply(null, new Uint8Array(inputBuffer))); + } + //********************************************************************************** + /** + * Function converting ASN.1 internal string into ArrayBuffer + * @returns {ArrayBuffer} + */ + toBuffer() { + const str = this.toString(); + + const buffer = new ArrayBuffer(str.length); + const view = new Uint8Array(buffer); + + for (let i = 0; i < str.length; i++) view[i] = str.charCodeAt(i); + + return buffer; + } + //********************************************************************************** + /** + * Function converting "Date" object into ASN.1 internal string + * @param {!Date} inputDate JavaScript "Date" object + */ + fromDate(inputDate) { + this.year = inputDate.getUTCFullYear(); + this.month = inputDate.getUTCMonth() + 1; + this.day = inputDate.getUTCDate(); + this.hour = inputDate.getUTCHours(); + this.minute = inputDate.getUTCMinutes(); + this.second = inputDate.getUTCSeconds(); + } + //********************************************************************************** + //noinspection JSUnusedGlobalSymbols + /** + * Function converting ASN.1 internal string into "Date" object + * @returns {Date} + */ + toDate() { + return new Date(Date.UTC(this.year, this.month - 1, this.day, this.hour, this.minute, this.second)); + } + //********************************************************************************** + /** + * Function converting JavaScript string into ASN.1 internal class + * @param {!string} inputString ASN.1 BER encoded array + */ + fromString(inputString) { + //region Parse input string + const parser = /(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})Z/ig; + const parserArray = parser.exec(inputString); + if (parserArray === null) { + this.error = "Wrong input string for convertion"; + return; + } + //endregion + + //region Store parsed values + const year = parseInt(parserArray[1], 10); + if (year >= 50) this.year = 1900 + year;else this.year = 2000 + year; + + this.month = parseInt(parserArray[2], 10); + this.day = parseInt(parserArray[3], 10); + this.hour = parseInt(parserArray[4], 10); + this.minute = parseInt(parserArray[5], 10); + this.second = parseInt(parserArray[6], 10); + //endregion + } + //********************************************************************************** + /** + * Function converting ASN.1 internal class into JavaScript string + * @returns {string} + */ + toString() { + const outputArray = new Array(7); + + outputArray[0] = (0, _pvutils.padNumber)(this.year < 2000 ? this.year - 1900 : this.year - 2000, 2); + outputArray[1] = (0, _pvutils.padNumber)(this.month, 2); + outputArray[2] = (0, _pvutils.padNumber)(this.day, 2); + outputArray[3] = (0, _pvutils.padNumber)(this.hour, 2); + outputArray[4] = (0, _pvutils.padNumber)(this.minute, 2); + outputArray[5] = (0, _pvutils.padNumber)(this.second, 2); + outputArray[6] = "Z"; + + return outputArray.join(""); + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "UTCTime"; + } + //********************************************************************************** + /** + * Convertion for the block to JSON object + * @returns {Object} + */ + toJSON() { + let object = {}; + + //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object + try { + object = super.toJSON(); + } catch (ex) {} + //endregion + + object.year = this.year; + object.month = this.month; + object.day = this.day; + object.hour = this.hour; + object.minute = this.minute; + object.second = this.second; + + return object; + } + //********************************************************************************** +} +exports.UTCTime = UTCTime; //************************************************************************************** +/** + * @extends VisibleString + */ + +class GeneralizedTime extends VisibleString { + //********************************************************************************** + /** + * Constructor for "GeneralizedTime" class + * @param {Object} [parameters={}] + * @property {string} [value] String representatio of the date + * @property {Date} [valueDate] JavaScript "Date" object + */ + constructor(parameters = {}) { + super(parameters); + + this.year = 0; + this.month = 0; + this.day = 0; + this.hour = 0; + this.minute = 0; + this.second = 0; + this.millisecond = 0; + + //region Create UTCTime from ASN.1 UTC string value + if ("value" in parameters) { + this.fromString(parameters.value); + + this.valueBlock.valueHex = new ArrayBuffer(parameters.value.length); + const view = new Uint8Array(this.valueBlock.valueHex); + + for (let i = 0; i < parameters.value.length; i++) view[i] = parameters.value.charCodeAt(i); + } + //endregion + //region Create GeneralizedTime from JavaScript Date type + if ("valueDate" in parameters) { + this.fromDate(parameters.valueDate); + this.valueBlock.valueHex = this.toBuffer(); + } + //endregion + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 24; // GeneralizedTime + } + //********************************************************************************** + /** + * Base function for converting block from BER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {number} Offset after least decoded byte + */ + fromBER(inputBuffer, inputOffset, inputLength) { + const resultOffset = this.valueBlock.fromBER(inputBuffer, inputOffset, this.lenBlock.isIndefiniteForm === true ? inputLength : this.lenBlock.length); + if (resultOffset === -1) { + this.error = this.valueBlock.error; + return resultOffset; + } + + this.fromBuffer(this.valueBlock.valueHex); + + if (this.idBlock.error.length === 0) this.blockLength += this.idBlock.blockLength; + + if (this.lenBlock.error.length === 0) this.blockLength += this.lenBlock.blockLength; + + if (this.valueBlock.error.length === 0) this.blockLength += this.valueBlock.blockLength; + + return resultOffset; + } + //********************************************************************************** + /** + * Function converting ArrayBuffer into ASN.1 internal string + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + */ + fromBuffer(inputBuffer) { + this.fromString(String.fromCharCode.apply(null, new Uint8Array(inputBuffer))); + } + //********************************************************************************** + /** + * Function converting ASN.1 internal string into ArrayBuffer + * @returns {ArrayBuffer} + */ + toBuffer() { + const str = this.toString(); + + const buffer = new ArrayBuffer(str.length); + const view = new Uint8Array(buffer); + + for (let i = 0; i < str.length; i++) view[i] = str.charCodeAt(i); + + return buffer; + } + //********************************************************************************** + /** + * Function converting "Date" object into ASN.1 internal string + * @param {!Date} inputDate JavaScript "Date" object + */ + fromDate(inputDate) { + this.year = inputDate.getUTCFullYear(); + this.month = inputDate.getUTCMonth() + 1; + this.day = inputDate.getUTCDate(); + this.hour = inputDate.getUTCHours(); + this.minute = inputDate.getUTCMinutes(); + this.second = inputDate.getUTCSeconds(); + this.millisecond = inputDate.getUTCMilliseconds(); + } + //********************************************************************************** + //noinspection JSUnusedGlobalSymbols + /** + * Function converting ASN.1 internal string into "Date" object + * @returns {Date} + */ + toDate() { + return new Date(Date.UTC(this.year, this.month - 1, this.day, this.hour, this.minute, this.second, this.millisecond)); + } + //********************************************************************************** + /** + * Function converting JavaScript string into ASN.1 internal class + * @param {!string} inputString ASN.1 BER encoded array + */ + fromString(inputString) { + //region Initial variables + let isUTC = false; + + let timeString = ""; + let dateTimeString = ""; + let fractionPart = 0; + + let parser; + + let hourDifference = 0; + let minuteDifference = 0; + //endregion + + //region Convert as UTC time + if (inputString[inputString.length - 1] === "Z") { + timeString = inputString.substr(0, inputString.length - 1); + + isUTC = true; + } + //endregion + //region Convert as local time + else { + //noinspection JSPrimitiveTypeWrapperUsage + const number = new Number(inputString[inputString.length - 1]); + + if (isNaN(number.valueOf())) throw new Error("Wrong input string for convertion"); + + timeString = inputString; + } + //endregion + + //region Check that we do not have a "+" and "-" symbols inside UTC time + if (isUTC) { + if (timeString.indexOf("+") !== -1) throw new Error("Wrong input string for convertion"); + + if (timeString.indexOf("-") !== -1) throw new Error("Wrong input string for convertion"); + } + //endregion + //region Get "UTC time difference" in case of local time + else { + let multiplier = 1; + let differencePosition = timeString.indexOf("+"); + let differenceString = ""; + + if (differencePosition === -1) { + differencePosition = timeString.indexOf("-"); + multiplier = -1; + } + + if (differencePosition !== -1) { + differenceString = timeString.substr(differencePosition + 1); + timeString = timeString.substr(0, differencePosition); + + if (differenceString.length !== 2 && differenceString.length !== 4) throw new Error("Wrong input string for convertion"); + + //noinspection JSPrimitiveTypeWrapperUsage + let number = new Number(differenceString.substr(0, 2)); + + if (isNaN(number.valueOf())) throw new Error("Wrong input string for convertion"); + + hourDifference = multiplier * number; + + if (differenceString.length === 4) { + //noinspection JSPrimitiveTypeWrapperUsage + number = new Number(differenceString.substr(2, 2)); + + if (isNaN(number.valueOf())) throw new Error("Wrong input string for convertion"); + + minuteDifference = multiplier * number; + } + } + } + //endregion + + //region Get position of fraction point + let fractionPointPosition = timeString.indexOf("."); // Check for "full stop" symbol + if (fractionPointPosition === -1) fractionPointPosition = timeString.indexOf(","); // Check for "comma" symbol + //endregion + + //region Get fraction part + if (fractionPointPosition !== -1) { + //noinspection JSPrimitiveTypeWrapperUsage + const fractionPartCheck = new Number(`0${timeString.substr(fractionPointPosition)}`); + + if (isNaN(fractionPartCheck.valueOf())) throw new Error("Wrong input string for convertion"); + + fractionPart = fractionPartCheck.valueOf(); + + dateTimeString = timeString.substr(0, fractionPointPosition); + } else dateTimeString = timeString; + //endregion + + //region Parse internal date + switch (true) { + case dateTimeString.length === 8: + // "YYYYMMDD" + parser = /(\d{4})(\d{2})(\d{2})/ig; + if (fractionPointPosition !== -1) throw new Error("Wrong input string for convertion"); // Here we should not have a "fraction point" + break; + case dateTimeString.length === 10: + // "YYYYMMDDHH" + parser = /(\d{4})(\d{2})(\d{2})(\d{2})/ig; + + if (fractionPointPosition !== -1) { + let fractionResult = 60 * fractionPart; + this.minute = Math.floor(fractionResult); + + fractionResult = 60 * (fractionResult - this.minute); + this.second = Math.floor(fractionResult); + + fractionResult = 1000 * (fractionResult - this.second); + this.millisecond = Math.floor(fractionResult); + } + break; + case dateTimeString.length === 12: + // "YYYYMMDDHHMM" + parser = /(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})/ig; + + if (fractionPointPosition !== -1) { + let fractionResult = 60 * fractionPart; + this.second = Math.floor(fractionResult); + + fractionResult = 1000 * (fractionResult - this.second); + this.millisecond = Math.floor(fractionResult); + } + break; + case dateTimeString.length === 14: + // "YYYYMMDDHHMMSS" + parser = /(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/ig; + + if (fractionPointPosition !== -1) { + const fractionResult = 1000 * fractionPart; + this.millisecond = Math.floor(fractionResult); + } + break; + default: + throw new Error("Wrong input string for convertion"); + } + //endregion + + //region Put parsed values at right places + const parserArray = parser.exec(dateTimeString); + if (parserArray === null) throw new Error("Wrong input string for convertion"); + + for (let j = 1; j < parserArray.length; j++) { + switch (j) { + case 1: + this.year = parseInt(parserArray[j], 10); + break; + case 2: + this.month = parseInt(parserArray[j], 10); + break; + case 3: + this.day = parseInt(parserArray[j], 10); + break; + case 4: + this.hour = parseInt(parserArray[j], 10) + hourDifference; + break; + case 5: + this.minute = parseInt(parserArray[j], 10) + minuteDifference; + break; + case 6: + this.second = parseInt(parserArray[j], 10); + break; + default: + throw new Error("Wrong input string for convertion"); + } + } + //endregion + + //region Get final date + if (isUTC === false) { + const tempDate = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond); + + this.year = tempDate.getUTCFullYear(); + this.month = tempDate.getUTCMonth(); + this.day = tempDate.getUTCDay(); + this.hour = tempDate.getUTCHours(); + this.minute = tempDate.getUTCMinutes(); + this.second = tempDate.getUTCSeconds(); + this.millisecond = tempDate.getUTCMilliseconds(); + } + //endregion + } + //********************************************************************************** + /** + * Function converting ASN.1 internal class into JavaScript string + * @returns {string} + */ + toString() { + const outputArray = []; + + outputArray.push((0, _pvutils.padNumber)(this.year, 4)); + outputArray.push((0, _pvutils.padNumber)(this.month, 2)); + outputArray.push((0, _pvutils.padNumber)(this.day, 2)); + outputArray.push((0, _pvutils.padNumber)(this.hour, 2)); + outputArray.push((0, _pvutils.padNumber)(this.minute, 2)); + outputArray.push((0, _pvutils.padNumber)(this.second, 2)); + if (this.millisecond !== 0) { + outputArray.push("."); + outputArray.push((0, _pvutils.padNumber)(this.millisecond, 3)); + } + outputArray.push("Z"); + + return outputArray.join(""); + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "GeneralizedTime"; + } + //********************************************************************************** + /** + * Convertion for the block to JSON object + * @returns {Object} + */ + toJSON() { + let object = {}; + + //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object + try { + object = super.toJSON(); + } catch (ex) {} + //endregion + + object.year = this.year; + object.month = this.month; + object.day = this.day; + object.hour = this.hour; + object.minute = this.minute; + object.second = this.second; + object.millisecond = this.millisecond; + + return object; + } + //********************************************************************************** +} +exports.GeneralizedTime = GeneralizedTime; //************************************************************************************** +/** + * @extends Utf8String + */ + +class DATE extends Utf8String { + //********************************************************************************** + /** + * Constructor for "DATE" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) { + super(parameters); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 31; // DATE + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "DATE"; + } + //********************************************************************************** +} +exports.DATE = DATE; //************************************************************************************** +/** + * @extends Utf8String + */ + +class TimeOfDay extends Utf8String { + //********************************************************************************** + /** + * Constructor for "TimeOfDay" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) { + super(parameters); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 32; // TimeOfDay + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "TimeOfDay"; + } + //********************************************************************************** +} +exports.TimeOfDay = TimeOfDay; //************************************************************************************** +/** + * @extends Utf8String + */ + +class DateTime extends Utf8String { + //********************************************************************************** + /** + * Constructor for "DateTime" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) { + super(parameters); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 33; // DateTime + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "DateTime"; + } + //********************************************************************************** +} +exports.DateTime = DateTime; //************************************************************************************** +/** + * @extends Utf8String + */ + +class Duration extends Utf8String { + //********************************************************************************** + /** + * Constructor for "Duration" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) { + super(parameters); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 34; // Duration + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "Duration"; + } + //********************************************************************************** +} +exports.Duration = Duration; //************************************************************************************** +/** + * @extends Utf8String + */ + +class TIME extends Utf8String { + //********************************************************************************** + /** + * Constructor for "Time" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) { + super(parameters); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 14; // Time + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "TIME"; + } + //********************************************************************************** +} +exports.TIME = TIME; //************************************************************************************** +//endregion +//************************************************************************************** +//region Declaration of special ASN.1 schema type Choice +//************************************************************************************** + +class Choice { + //********************************************************************************** + /** + * Constructor for "Choice" class + * @param {Object} [parameters={}] + * @property {Array} [value] Array of ASN.1 types for make a choice from + * @property {boolean} [optional] + */ + constructor(parameters = {}) { + this.value = (0, _pvutils.getParametersValue)(parameters, "value", []); + this.optional = (0, _pvutils.getParametersValue)(parameters, "optional", false); + } + //********************************************************************************** +} +exports.Choice = Choice; //************************************************************************************** +//endregion +//************************************************************************************** +//region Declaration of special ASN.1 schema type Any +//************************************************************************************** + +class Any { + //********************************************************************************** + /** + * Constructor for "Any" class + * @param {Object} [parameters={}] + * @property {string} [name] + * @property {boolean} [optional] + */ + constructor(parameters = {}) { + this.name = (0, _pvutils.getParametersValue)(parameters, "name", ""); + this.optional = (0, _pvutils.getParametersValue)(parameters, "optional", false); + } + //********************************************************************************** +} +exports.Any = Any; //************************************************************************************** +//endregion +//************************************************************************************** +//region Declaration of special ASN.1 schema type Repeated +//************************************************************************************** + +class Repeated { + //********************************************************************************** + /** + * Constructor for "Repeated" class + * @param {Object} [parameters={}] + * @property {string} [name] + * @property {boolean} [optional] + */ + constructor(parameters = {}) { + this.name = (0, _pvutils.getParametersValue)(parameters, "name", ""); + this.optional = (0, _pvutils.getParametersValue)(parameters, "optional", false); + this.value = (0, _pvutils.getParametersValue)(parameters, "value", new Any()); + this.local = (0, _pvutils.getParametersValue)(parameters, "local", false); // Could local or global array to store elements + } + //********************************************************************************** +} +exports.Repeated = Repeated; //************************************************************************************** +//endregion +//************************************************************************************** +//region Declaration of special ASN.1 schema type RawData +//************************************************************************************** +/** + * @description Special class providing ability to have "toBER/fromBER" for raw ArrayBuffer + */ + +class RawData { + //********************************************************************************** + /** + * Constructor for "Repeated" class + * @param {Object} [parameters={}] + * @property {string} [name] + * @property {boolean} [optional] + */ + constructor(parameters = {}) { + this.data = (0, _pvutils.getParametersValue)(parameters, "data", new ArrayBuffer(0)); + } + //********************************************************************************** + /** + * Base function for converting block from BER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {number} Offset after least decoded byte + */ + fromBER(inputBuffer, inputOffset, inputLength) { + this.data = inputBuffer.slice(inputOffset, inputLength); + return inputOffset + inputLength; + } + //********************************************************************************** + /** + * Encoding of current ASN.1 block into ASN.1 encoded array (BER rules) + * @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes + * @returns {ArrayBuffer} + */ + toBER(sizeOnly = false) { + return this.data; + } + //********************************************************************************** +} +exports.RawData = RawData; //************************************************************************************** +//endregion +//************************************************************************************** +//region Major ASN.1 BER decoding function +//************************************************************************************** +/** + * Internal library function for decoding ASN.1 BER + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {{offset: number, result: Object}} + */ + +function LocalFromBER(inputBuffer, inputOffset, inputLength) { + const incomingOffset = inputOffset; // Need to store initial offset since "inputOffset" is changing in the function + + //region Local function changing a type for ASN.1 classes + function localChangeType(inputObject, newType) { + if (inputObject instanceof newType) return inputObject; + + const newObject = new newType(); + newObject.idBlock = inputObject.idBlock; + newObject.lenBlock = inputObject.lenBlock; + newObject.warnings = inputObject.warnings; + //noinspection JSCheckFunctionSignatures + newObject.valueBeforeDecode = inputObject.valueBeforeDecode.slice(0); + + return newObject; + } + //endregion + + //region Create a basic ASN.1 type since we need to return errors and warnings from the function + let returnObject = new BaseBlock({}, Object); + //endregion + + //region Basic check for parameters + if ((0, _pvutils.checkBufferParams)(new LocalBaseBlock(), inputBuffer, inputOffset, inputLength) === false) { + returnObject.error = "Wrong input parameters"; + return { + offset: -1, + result: returnObject + }; + } + //endregion + + //region Getting Uint8Array from ArrayBuffer + const intBuffer = new Uint8Array(inputBuffer, inputOffset, inputLength); + //endregion + + //region Initial checks + if (intBuffer.length === 0) { + this.error = "Zero buffer length"; + return { + offset: -1, + result: returnObject + }; + } + //endregion + + //region Decode indentifcation block of ASN.1 BER structure + let resultOffset = returnObject.idBlock.fromBER(inputBuffer, inputOffset, inputLength); + returnObject.warnings.concat(returnObject.idBlock.warnings); + if (resultOffset === -1) { + returnObject.error = returnObject.idBlock.error; + return { + offset: -1, + result: returnObject + }; + } + + inputOffset = resultOffset; + inputLength -= returnObject.idBlock.blockLength; + //endregion + + //region Decode length block of ASN.1 BER structure + resultOffset = returnObject.lenBlock.fromBER(inputBuffer, inputOffset, inputLength); + returnObject.warnings.concat(returnObject.lenBlock.warnings); + if (resultOffset === -1) { + returnObject.error = returnObject.lenBlock.error; + return { + offset: -1, + result: returnObject + }; + } + + inputOffset = resultOffset; + inputLength -= returnObject.lenBlock.blockLength; + //endregion + + //region Check for usign indefinite length form in encoding for primitive types + if (returnObject.idBlock.isConstructed === false && returnObject.lenBlock.isIndefiniteForm === true) { + returnObject.error = "Indefinite length form used for primitive encoding form"; + return { + offset: -1, + result: returnObject + }; + } + //endregion + + //region Switch ASN.1 block type + let newASN1Type = BaseBlock; + + switch (returnObject.idBlock.tagClass) { + //region UNIVERSAL + case 1: + //region Check for reserved tag numbers + if (returnObject.idBlock.tagNumber >= 37 && returnObject.idBlock.isHexOnly === false) { + returnObject.error = "UNIVERSAL 37 and upper tags are reserved by ASN.1 standard"; + return { + offset: -1, + result: returnObject + }; + } + //endregion + + switch (returnObject.idBlock.tagNumber) { + //region EndOfContent type + case 0: + //region Check for EndOfContent type + if (returnObject.idBlock.isConstructed === true && returnObject.lenBlock.length > 0) { + returnObject.error = "Type [UNIVERSAL 0] is reserved"; + return { + offset: -1, + result: returnObject + }; + } + //endregion + + newASN1Type = EndOfContent; + + break; + //endregion + //region Boolean type + case 1: + newASN1Type = Boolean; + break; + //endregion + //region Integer type + case 2: + newASN1Type = Integer; + break; + //endregion + //region BitString type + case 3: + newASN1Type = BitString; + break; + //endregion + //region OctetString type + case 4: + newASN1Type = OctetString; + break; + //endregion + //region Null type + case 5: + newASN1Type = Null; + break; + //endregion + //region OBJECT IDENTIFIER type + case 6: + newASN1Type = ObjectIdentifier; + break; + //endregion + //region Enumerated type + case 10: + newASN1Type = Enumerated; + break; + //endregion + //region Utf8String type + case 12: + newASN1Type = Utf8String; + break; + //endregion + //region Time type + case 14: + newASN1Type = TIME; + break; + //endregion + //region ASN.1 reserved type + case 15: + returnObject.error = "[UNIVERSAL 15] is reserved by ASN.1 standard"; + return { + offset: -1, + result: returnObject + }; + //endregion + //region Sequence type + case 16: + newASN1Type = Sequence; + break; + //endregion + //region Set type + case 17: + newASN1Type = Set; + break; + //endregion + //region NumericString type + case 18: + newASN1Type = NumericString; + break; + //endregion + //region PrintableString type + case 19: + newASN1Type = PrintableString; + break; + //endregion + //region TeletexString type + case 20: + newASN1Type = TeletexString; + break; + //endregion + //region VideotexString type + case 21: + newASN1Type = VideotexString; + break; + //endregion + //region IA5String type + case 22: + newASN1Type = IA5String; + break; + //endregion + //region UTCTime type + case 23: + newASN1Type = UTCTime; + break; + //endregion + //region GeneralizedTime type + case 24: + newASN1Type = GeneralizedTime; + break; + //endregion + //region GraphicString type + case 25: + newASN1Type = GraphicString; + break; + //endregion + //region VisibleString type + case 26: + newASN1Type = VisibleString; + break; + //endregion + //region GeneralString type + case 27: + newASN1Type = GeneralString; + break; + //endregion + //region UniversalString type + case 28: + newASN1Type = UniversalString; + break; + //endregion + //region CharacterString type + case 29: + newASN1Type = CharacterString; + break; + //endregion + //region BmpString type + case 30: + newASN1Type = BmpString; + break; + //endregion + //region DATE type + case 31: + newASN1Type = DATE; + break; + //endregion + //region TimeOfDay type + case 32: + newASN1Type = TimeOfDay; + break; + //endregion + //region Date-Time type + case 33: + newASN1Type = DateTime; + break; + //endregion + //region Duration type + case 34: + newASN1Type = Duration; + break; + //endregion + //region default + default: + { + let newObject; + + if (returnObject.idBlock.isConstructed === true) newObject = new Constructed();else newObject = new Primitive(); + + newObject.idBlock = returnObject.idBlock; + newObject.lenBlock = returnObject.lenBlock; + newObject.warnings = returnObject.warnings; + + returnObject = newObject; + + resultOffset = returnObject.fromBER(inputBuffer, inputOffset, inputLength); + } + //endregion + } + break; + //endregion + //region All other tag classes + case 2: // APPLICATION + case 3: // CONTEXT-SPECIFIC + case 4: // PRIVATE + default: + { + if (returnObject.idBlock.isConstructed === true) newASN1Type = Constructed;else newASN1Type = Primitive; + } + //endregion + } + //endregion + + //region Change type and perform BER decoding + returnObject = localChangeType(returnObject, newASN1Type); + resultOffset = returnObject.fromBER(inputBuffer, inputOffset, returnObject.lenBlock.isIndefiniteForm === true ? inputLength : returnObject.lenBlock.length); + //endregion + + //region Coping incoming buffer for entire ASN.1 block + returnObject.valueBeforeDecode = inputBuffer.slice(incomingOffset, incomingOffset + returnObject.blockLength); + //endregion + + return { + offset: resultOffset, + result: returnObject + }; +} +//************************************************************************************** +/** + * Major function for decoding ASN.1 BER array into internal library structuries + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array of bytes + */ +function fromBER(inputBuffer) { + if (inputBuffer.byteLength === 0) { + const result = new BaseBlock({}, Object); + result.error = "Input buffer has zero length"; + + return { + offset: -1, + result + }; + } + + return LocalFromBER(inputBuffer, 0, inputBuffer.byteLength); +} +//************************************************************************************** +//endregion +//************************************************************************************** +//region Major scheme verification function +//************************************************************************************** +/** + * Compare of two ASN.1 object trees + * @param {!Object} root Root of input ASN.1 object tree + * @param {!Object} inputData Input ASN.1 object tree + * @param {!Object} inputSchema Input ASN.1 schema to compare with + * @return {{verified: boolean}|{verified:boolean, result: Object}} + */ +function compareSchema(root, inputData, inputSchema) { + //region Special case for Choice schema element type + if (inputSchema instanceof Choice) { + const choiceResult = false; + + for (let j = 0; j < inputSchema.value.length; j++) { + const result = compareSchema(root, inputData, inputSchema.value[j]); + if (result.verified === true) { + return { + verified: true, + result: root + }; + } + } + + if (choiceResult === false) { + const _result = { + verified: false, + result: { + error: "Wrong values for Choice type" + } + }; + + if (inputSchema.hasOwnProperty("name")) _result.name = inputSchema.name; + + return _result; + } + } + //endregion + + //region Special case for Any schema element type + if (inputSchema instanceof Any) { + //region Add named component of ASN.1 schema + if (inputSchema.hasOwnProperty("name")) root[inputSchema.name] = inputData; + //endregion + + return { + verified: true, + result: root + }; + } + //endregion + + //region Initial check + if (root instanceof Object === false) { + return { + verified: false, + result: { error: "Wrong root object" } + }; + } + + if (inputData instanceof Object === false) { + return { + verified: false, + result: { error: "Wrong ASN.1 data" } + }; + } + + if (inputSchema instanceof Object === false) { + return { + verified: false, + result: { error: "Wrong ASN.1 schema" } + }; + } + + if ("idBlock" in inputSchema === false) { + return { + verified: false, + result: { error: "Wrong ASN.1 schema" } + }; + } + //endregion + + //region Comparing idBlock properties in ASN.1 data and ASN.1 schema + //region Encode and decode ASN.1 schema idBlock + /// This encoding/decoding is neccessary because could be an errors in schema definition + if ("fromBER" in inputSchema.idBlock === false) { + return { + verified: false, + result: { error: "Wrong ASN.1 schema" } + }; + } + + if ("toBER" in inputSchema.idBlock === false) { + return { + verified: false, + result: { error: "Wrong ASN.1 schema" } + }; + } + + const encodedId = inputSchema.idBlock.toBER(false); + if (encodedId.byteLength === 0) { + return { + verified: false, + result: { error: "Error encoding idBlock for ASN.1 schema" } + }; + } + + const decodedOffset = inputSchema.idBlock.fromBER(encodedId, 0, encodedId.byteLength); + if (decodedOffset === -1) { + return { + verified: false, + result: { error: "Error decoding idBlock for ASN.1 schema" } + }; + } + //endregion + + //region tagClass + if (inputSchema.idBlock.hasOwnProperty("tagClass") === false) { + return { + verified: false, + result: { error: "Wrong ASN.1 schema" } + }; + } + + if (inputSchema.idBlock.tagClass !== inputData.idBlock.tagClass) { + return { + verified: false, + result: root + }; + } + //endregion + //region tagNumber + if (inputSchema.idBlock.hasOwnProperty("tagNumber") === false) { + return { + verified: false, + result: { error: "Wrong ASN.1 schema" } + }; + } + + if (inputSchema.idBlock.tagNumber !== inputData.idBlock.tagNumber) { + return { + verified: false, + result: root + }; + } + //endregion + //region isConstructed + if (inputSchema.idBlock.hasOwnProperty("isConstructed") === false) { + return { + verified: false, + result: { error: "Wrong ASN.1 schema" } + }; + } + + if (inputSchema.idBlock.isConstructed !== inputData.idBlock.isConstructed) { + return { + verified: false, + result: root + }; + } + //endregion + //region isHexOnly + if ("isHexOnly" in inputSchema.idBlock === false) // Since 'isHexOnly' is an inhirited property + { + return { + verified: false, + result: { error: "Wrong ASN.1 schema" } + }; + } + + if (inputSchema.idBlock.isHexOnly !== inputData.idBlock.isHexOnly) { + return { + verified: false, + result: root + }; + } + //endregion + //region valueHex + if (inputSchema.idBlock.isHexOnly === true) { + if ("valueHex" in inputSchema.idBlock === false) // Since 'valueHex' is an inhirited property + { + return { + verified: false, + result: { error: "Wrong ASN.1 schema" } + }; + } + + const schemaView = new Uint8Array(inputSchema.idBlock.valueHex); + const asn1View = new Uint8Array(inputData.idBlock.valueHex); + + if (schemaView.length !== asn1View.length) { + return { + verified: false, + result: root + }; + } + + for (let i = 0; i < schemaView.length; i++) { + if (schemaView[i] !== asn1View[1]) { + return { + verified: false, + result: root + }; + } + } + } + //endregion + //endregion + + //region Add named component of ASN.1 schema + if (inputSchema.hasOwnProperty("name")) { + inputSchema.name = inputSchema.name.replace(/^\s+|\s+$/g, ""); + if (inputSchema.name !== "") root[inputSchema.name] = inputData; + } + //endregion + + //region Getting next ASN.1 block for comparition + if (inputSchema.idBlock.isConstructed === true) { + let admission = 0; + let result = { verified: false }; + + let maxLength = inputSchema.valueBlock.value.length; + + if (maxLength > 0) { + if (inputSchema.valueBlock.value[0] instanceof Repeated) maxLength = inputData.valueBlock.value.length; + } + + //region Special case when constructive value has no elements + if (maxLength === 0) { + return { + verified: true, + result: root + }; + } + //endregion + + //region Special case when "inputData" has no values and "inputSchema" has all optional values + if (inputData.valueBlock.value.length === 0 && inputSchema.valueBlock.value.length !== 0) { + let _optional = true; + + for (let i = 0; i < inputSchema.valueBlock.value.length; i++) _optional = _optional && (inputSchema.valueBlock.value[i].optional || false); + + if (_optional === true) { + return { + verified: true, + result: root + }; + } + + //region Delete early added name of block + if (inputSchema.hasOwnProperty("name")) { + inputSchema.name = inputSchema.name.replace(/^\s+|\s+$/g, ""); + if (inputSchema.name !== "") delete root[inputSchema.name]; + } + //endregion + + root.error = "Inconsistent object length"; + + return { + verified: false, + result: root + }; + } + //endregion + + for (let i = 0; i < maxLength; i++) { + //region Special case when there is an "optional" element of ASN.1 schema at the end + if (i - admission >= inputData.valueBlock.value.length) { + if (inputSchema.valueBlock.value[i].optional === false) { + const _result = { + verified: false, + result: root + }; + + root.error = "Inconsistent length between ASN.1 data and schema"; + + //region Delete early added name of block + if (inputSchema.hasOwnProperty("name")) { + inputSchema.name = inputSchema.name.replace(/^\s+|\s+$/g, ""); + if (inputSchema.name !== "") { + delete root[inputSchema.name]; + _result.name = inputSchema.name; + } + } + //endregion + + return _result; + } + } + //endregion + else { + //region Special case for Repeated type of ASN.1 schema element + if (inputSchema.valueBlock.value[0] instanceof Repeated) { + result = compareSchema(root, inputData.valueBlock.value[i], inputSchema.valueBlock.value[0].value); + if (result.verified === false) { + if (inputSchema.valueBlock.value[0].optional === true) admission++;else { + //region Delete early added name of block + if (inputSchema.hasOwnProperty("name")) { + inputSchema.name = inputSchema.name.replace(/^\s+|\s+$/g, ""); + if (inputSchema.name !== "") delete root[inputSchema.name]; + } + //endregion + + return result; + } + } + + if ("name" in inputSchema.valueBlock.value[0] && inputSchema.valueBlock.value[0].name.length > 0) { + let arrayRoot = {}; + + if ("local" in inputSchema.valueBlock.value[0] && inputSchema.valueBlock.value[0].local === true) arrayRoot = inputData;else arrayRoot = root; + + if (typeof arrayRoot[inputSchema.valueBlock.value[0].name] === "undefined") arrayRoot[inputSchema.valueBlock.value[0].name] = []; + + arrayRoot[inputSchema.valueBlock.value[0].name].push(inputData.valueBlock.value[i]); + } + } + //endregion + else { + result = compareSchema(root, inputData.valueBlock.value[i - admission], inputSchema.valueBlock.value[i]); + if (result.verified === false) { + if (inputSchema.valueBlock.value[i].optional === true) admission++;else { + //region Delete early added name of block + if (inputSchema.hasOwnProperty("name")) { + inputSchema.name = inputSchema.name.replace(/^\s+|\s+$/g, ""); + if (inputSchema.name !== "") delete root[inputSchema.name]; + } + //endregion + + return result; + } + } + } + } + } + + if (result.verified === false) // The situation may take place if last element is "optional" and verification failed + { + const _result = { + verified: false, + result: root + }; + + //region Delete early added name of block + if (inputSchema.hasOwnProperty("name")) { + inputSchema.name = inputSchema.name.replace(/^\s+|\s+$/g, ""); + if (inputSchema.name !== "") { + delete root[inputSchema.name]; + _result.name = inputSchema.name; + } + } + //endregion + + return _result; + } + + return { + verified: true, + result: root + }; + } + //endregion + //region Ability to parse internal value for primitive-encoded value (value of OctetString, for example) + if ("primitiveSchema" in inputSchema && "valueHex" in inputData.valueBlock) { + //region Decoding of raw ASN.1 data + const asn1 = fromBER(inputData.valueBlock.valueHex); + if (asn1.offset === -1) { + const _result = { + verified: false, + result: asn1.result + }; + + //region Delete early added name of block + if (inputSchema.hasOwnProperty("name")) { + inputSchema.name = inputSchema.name.replace(/^\s+|\s+$/g, ""); + if (inputSchema.name !== "") { + delete root[inputSchema.name]; + _result.name = inputSchema.name; + } + } + //endregion + + return _result; + } + //endregion + + return compareSchema(root, asn1.result, inputSchema.primitiveSchema); + } + + return { + verified: true, + result: root + }; + //endregion +} +//************************************************************************************** +//noinspection JSUnusedGlobalSymbols +/** + * ASN.1 schema verification for ArrayBuffer data + * @param {!ArrayBuffer} inputBuffer Input BER-encoded ASN.1 data + * @param {!Object} inputSchema Input ASN.1 schema to verify against to + * @return {{verified: boolean}|{verified:boolean, result: Object}} + */ +function verifySchema(inputBuffer, inputSchema) { + //region Initial check + if (inputSchema instanceof Object === false) { + return { + verified: false, + result: { error: "Wrong ASN.1 schema type" } + }; + } + //endregion + + //region Decoding of raw ASN.1 data + const asn1 = fromBER(inputBuffer); + if (asn1.offset === -1) { + return { + verified: false, + result: asn1.result + }; + } + //endregion + + //region Compare ASN.1 struct with input schema + return compareSchema(asn1.result, asn1.result, inputSchema); + //endregion +} +//************************************************************************************** +//endregion +//************************************************************************************** +//region Major function converting JSON to ASN.1 objects +//************************************************************************************** +//noinspection JSUnusedGlobalSymbols +/** + * Converting from JSON to ASN.1 objects + * @param {string|Object} json JSON string or object to convert to ASN.1 objects + */ +function fromJSON(json) {} +// TODO Implement + +//************************************************************************************** +//endregion +//************************************************************************************** + +},{"pvutils":3}],3:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.getUTCDate = getUTCDate; +exports.getParametersValue = getParametersValue; +exports.bufferToHexCodes = bufferToHexCodes; +exports.checkBufferParams = checkBufferParams; +exports.utilFromBase = utilFromBase; +exports.utilToBase = utilToBase; +exports.utilConcatBuf = utilConcatBuf; +exports.utilConcatView = utilConcatView; +exports.utilDecodeTC = utilDecodeTC; +exports.utilEncodeTC = utilEncodeTC; +exports.isEqualBuffer = isEqualBuffer; +exports.padNumber = padNumber; +exports.toBase64 = toBase64; +exports.fromBase64 = fromBase64; +exports.arrayBufferToString = arrayBufferToString; +exports.stringToArrayBuffer = stringToArrayBuffer; +exports.nearestPowerOf2 = nearestPowerOf2; +exports.clearProps = clearProps; +//************************************************************************************** +/** + * Making UTC date from local date + * @param {Date} date Date to convert from + * @returns {Date} + */ +function getUTCDate(date) { + // noinspection NestedFunctionCallJS, MagicNumberJS + return new Date(date.getTime() + date.getTimezoneOffset() * 60000); +} +//************************************************************************************** +// noinspection FunctionWithMultipleReturnPointsJS +/** + * Get value for input parameters, or set a default value + * @param {Object} parameters + * @param {string} name + * @param defaultValue + */ +function getParametersValue(parameters, name, defaultValue) { + // noinspection ConstantOnRightSideOfComparisonJS, NonBlockStatementBodyJS + if (parameters instanceof Object === false) return defaultValue; + + // noinspection NonBlockStatementBodyJS + if (name in parameters) return parameters[name]; + + return defaultValue; +} +//************************************************************************************** +/** + * Converts "ArrayBuffer" into a hexdecimal string + * @param {ArrayBuffer} inputBuffer + * @param {number} [inputOffset=0] + * @param {number} [inputLength=inputBuffer.byteLength] + * @param {boolean} [insertSpace=false] + * @returns {string} + */ +function bufferToHexCodes(inputBuffer, inputOffset = 0, inputLength = inputBuffer.byteLength - inputOffset, insertSpace = false) { + let result = ""; + + var _iteratorNormalCompletion = true; + var _didIteratorError = false; + var _iteratorError = undefined; + + try { + for (var _iterator = new Uint8Array(inputBuffer, inputOffset, inputLength)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { + const item = _step.value; + + // noinspection ChainedFunctionCallJS + const str = item.toString(16).toUpperCase(); + + // noinspection ConstantOnRightSideOfComparisonJS, NonBlockStatementBodyJS + if (str.length === 1) result += "0"; + + result += str; + + // noinspection NonBlockStatementBodyJS + if (insertSpace) result += " "; + } + } catch (err) { + _didIteratorError = true; + _iteratorError = err; + } finally { + try { + if (!_iteratorNormalCompletion && _iterator.return) { + _iterator.return(); + } + } finally { + if (_didIteratorError) { + throw _iteratorError; + } + } + } + + return result.trim(); +} +//************************************************************************************** +// noinspection JSValidateJSDoc, FunctionWithMultipleReturnPointsJS +/** + * Check input "ArrayBuffer" for common functions + * @param {LocalBaseBlock} baseBlock + * @param {ArrayBuffer} inputBuffer + * @param {number} inputOffset + * @param {number} inputLength + * @returns {boolean} + */ +function checkBufferParams(baseBlock, inputBuffer, inputOffset, inputLength) { + // noinspection ConstantOnRightSideOfComparisonJS + if (inputBuffer instanceof ArrayBuffer === false) { + // noinspection JSUndefinedPropertyAssignment + baseBlock.error = "Wrong parameter: inputBuffer must be \"ArrayBuffer\""; + return false; + } + + // noinspection ConstantOnRightSideOfComparisonJS + if (inputBuffer.byteLength === 0) { + // noinspection JSUndefinedPropertyAssignment + baseBlock.error = "Wrong parameter: inputBuffer has zero length"; + return false; + } + + // noinspection ConstantOnRightSideOfComparisonJS + if (inputOffset < 0) { + // noinspection JSUndefinedPropertyAssignment + baseBlock.error = "Wrong parameter: inputOffset less than zero"; + return false; + } + + // noinspection ConstantOnRightSideOfComparisonJS + if (inputLength < 0) { + // noinspection JSUndefinedPropertyAssignment + baseBlock.error = "Wrong parameter: inputLength less than zero"; + return false; + } + + // noinspection ConstantOnRightSideOfComparisonJS + if (inputBuffer.byteLength - inputOffset - inputLength < 0) { + // noinspection JSUndefinedPropertyAssignment + baseBlock.error = "End of input reached before message was fully decoded (inconsistent offset and length values)"; + return false; + } + + return true; +} +//************************************************************************************** +// noinspection FunctionWithMultipleReturnPointsJS +/** + * Convert number from 2^base to 2^10 + * @param {Uint8Array} inputBuffer + * @param {number} inputBase + * @returns {number} + */ +function utilFromBase(inputBuffer, inputBase) { + let result = 0; + + // noinspection ConstantOnRightSideOfComparisonJS, NonBlockStatementBodyJS + if (inputBuffer.length === 1) return inputBuffer[0]; + + // noinspection ConstantOnRightSideOfComparisonJS, NonBlockStatementBodyJS + for (let i = inputBuffer.length - 1; i >= 0; i--) result += inputBuffer[inputBuffer.length - 1 - i] * Math.pow(2, inputBase * i); + + return result; +} +//************************************************************************************** +// noinspection FunctionWithMultipleLoopsJS, FunctionWithMultipleReturnPointsJS +/** + * Convert number from 2^10 to 2^base + * @param {!number} value The number to convert + * @param {!number} base The base for 2^base + * @param {number} [reserved=0] Pre-defined number of bytes in output array (-1 = limited by function itself) + * @returns {ArrayBuffer} + */ +function utilToBase(value, base, reserved = -1) { + const internalReserved = reserved; + let internalValue = value; + + let result = 0; + let biggest = Math.pow(2, base); + + // noinspection ConstantOnRightSideOfComparisonJS + for (let i = 1; i < 8; i++) { + if (value < biggest) { + let retBuf; + + // noinspection ConstantOnRightSideOfComparisonJS + if (internalReserved < 0) { + retBuf = new ArrayBuffer(i); + result = i; + } else { + // noinspection NonBlockStatementBodyJS + if (internalReserved < i) return new ArrayBuffer(0); + + retBuf = new ArrayBuffer(internalReserved); + + result = internalReserved; + } + + const retView = new Uint8Array(retBuf); + + // noinspection ConstantOnRightSideOfComparisonJS + for (let j = i - 1; j >= 0; j--) { + const basis = Math.pow(2, j * base); + + retView[result - j - 1] = Math.floor(internalValue / basis); + internalValue -= retView[result - j - 1] * basis; + } + + return retBuf; + } + + biggest *= Math.pow(2, base); + } + + return new ArrayBuffer(0); +} +//************************************************************************************** +// noinspection FunctionWithMultipleLoopsJS +/** + * Concatenate two ArrayBuffers + * @param {...ArrayBuffer} buffers Set of ArrayBuffer + */ +function utilConcatBuf(...buffers) { + //region Initial variables + let outputLength = 0; + let prevLength = 0; + //endregion + + //region Calculate output length + + // noinspection NonBlockStatementBodyJS + var _iteratorNormalCompletion2 = true; + var _didIteratorError2 = false; + var _iteratorError2 = undefined; + + try { + for (var _iterator2 = buffers[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { + const buffer = _step2.value; + + outputLength += buffer.byteLength; + } //endregion + } catch (err) { + _didIteratorError2 = true; + _iteratorError2 = err; + } finally { + try { + if (!_iteratorNormalCompletion2 && _iterator2.return) { + _iterator2.return(); + } + } finally { + if (_didIteratorError2) { + throw _iteratorError2; + } + } + } + + const retBuf = new ArrayBuffer(outputLength); + const retView = new Uint8Array(retBuf); + + var _iteratorNormalCompletion3 = true; + var _didIteratorError3 = false; + var _iteratorError3 = undefined; + + try { + for (var _iterator3 = buffers[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) { + const buffer = _step3.value; + + // noinspection NestedFunctionCallJS + retView.set(new Uint8Array(buffer), prevLength); + prevLength += buffer.byteLength; + } + } catch (err) { + _didIteratorError3 = true; + _iteratorError3 = err; + } finally { + try { + if (!_iteratorNormalCompletion3 && _iterator3.return) { + _iterator3.return(); + } + } finally { + if (_didIteratorError3) { + throw _iteratorError3; + } + } + } + + return retBuf; +} +//************************************************************************************** +// noinspection FunctionWithMultipleLoopsJS +/** + * Concatenate two Uint8Array + * @param {...Uint8Array} views Set of Uint8Array + */ +function utilConcatView(...views) { + //region Initial variables + let outputLength = 0; + let prevLength = 0; + //endregion + + //region Calculate output length + // noinspection NonBlockStatementBodyJS + var _iteratorNormalCompletion4 = true; + var _didIteratorError4 = false; + var _iteratorError4 = undefined; + + try { + for (var _iterator4 = views[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) { + const view = _step4.value; + + outputLength += view.length; + } //endregion + } catch (err) { + _didIteratorError4 = true; + _iteratorError4 = err; + } finally { + try { + if (!_iteratorNormalCompletion4 && _iterator4.return) { + _iterator4.return(); + } + } finally { + if (_didIteratorError4) { + throw _iteratorError4; + } + } + } + + const retBuf = new ArrayBuffer(outputLength); + const retView = new Uint8Array(retBuf); + + var _iteratorNormalCompletion5 = true; + var _didIteratorError5 = false; + var _iteratorError5 = undefined; + + try { + for (var _iterator5 = views[Symbol.iterator](), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) { + const view = _step5.value; + + retView.set(view, prevLength); + prevLength += view.length; + } + } catch (err) { + _didIteratorError5 = true; + _iteratorError5 = err; + } finally { + try { + if (!_iteratorNormalCompletion5 && _iterator5.return) { + _iterator5.return(); + } + } finally { + if (_didIteratorError5) { + throw _iteratorError5; + } + } + } + + return retView; +} +//************************************************************************************** +// noinspection FunctionWithMultipleLoopsJS +/** + * Decoding of "two complement" values + * The function must be called in scope of instance of "hexBlock" class ("valueHex" and "warnings" properties must be present) + * @returns {number} + */ +function utilDecodeTC() { + const buf = new Uint8Array(this.valueHex); + + // noinspection ConstantOnRightSideOfComparisonJS + if (this.valueHex.byteLength >= 2) { + //noinspection JSBitwiseOperatorUsage, ConstantOnRightSideOfComparisonJS, LocalVariableNamingConventionJS, MagicNumberJS, NonShortCircuitBooleanExpressionJS + const condition1 = buf[0] === 0xFF && buf[1] & 0x80; + // noinspection ConstantOnRightSideOfComparisonJS, LocalVariableNamingConventionJS, MagicNumberJS, NonShortCircuitBooleanExpressionJS + const condition2 = buf[0] === 0x00 && (buf[1] & 0x80) === 0x00; + + // noinspection NonBlockStatementBodyJS + if (condition1 || condition2) this.warnings.push("Needlessly long format"); + } + + //region Create big part of the integer + const bigIntBuffer = new ArrayBuffer(this.valueHex.byteLength); + const bigIntView = new Uint8Array(bigIntBuffer); + // noinspection NonBlockStatementBodyJS + for (let i = 0; i < this.valueHex.byteLength; i++) bigIntView[i] = 0; + + // noinspection MagicNumberJS, NonShortCircuitBooleanExpressionJS + bigIntView[0] = buf[0] & 0x80; // mask only the biggest bit + + const bigInt = utilFromBase(bigIntView, 8); + //endregion + + //region Create small part of the integer + const smallIntBuffer = new ArrayBuffer(this.valueHex.byteLength); + const smallIntView = new Uint8Array(smallIntBuffer); + // noinspection NonBlockStatementBodyJS + for (let j = 0; j < this.valueHex.byteLength; j++) smallIntView[j] = buf[j]; + + // noinspection MagicNumberJS + smallIntView[0] &= 0x7F; // mask biggest bit + + const smallInt = utilFromBase(smallIntView, 8); + //endregion + + return smallInt - bigInt; +} +//************************************************************************************** +// noinspection FunctionWithMultipleLoopsJS, FunctionWithMultipleReturnPointsJS +/** + * Encode integer value to "two complement" format + * @param {number} value Value to encode + * @returns {ArrayBuffer} + */ +function utilEncodeTC(value) { + // noinspection ConstantOnRightSideOfComparisonJS, ConditionalExpressionJS + const modValue = value < 0 ? value * -1 : value; + let bigInt = 128; + + // noinspection ConstantOnRightSideOfComparisonJS + for (let i = 1; i < 8; i++) { + if (modValue <= bigInt) { + // noinspection ConstantOnRightSideOfComparisonJS + if (value < 0) { + const smallInt = bigInt - modValue; + + const retBuf = utilToBase(smallInt, 8, i); + const retView = new Uint8Array(retBuf); + + // noinspection MagicNumberJS + retView[0] |= 0x80; + + return retBuf; + } + + let retBuf = utilToBase(modValue, 8, i); + let retView = new Uint8Array(retBuf); + + //noinspection JSBitwiseOperatorUsage, MagicNumberJS, NonShortCircuitBooleanExpressionJS + if (retView[0] & 0x80) { + //noinspection JSCheckFunctionSignatures + const tempBuf = retBuf.slice(0); + const tempView = new Uint8Array(tempBuf); + + retBuf = new ArrayBuffer(retBuf.byteLength + 1); + // noinspection ReuseOfLocalVariableJS + retView = new Uint8Array(retBuf); + + // noinspection NonBlockStatementBodyJS + for (let k = 0; k < tempBuf.byteLength; k++) retView[k + 1] = tempView[k]; + + // noinspection MagicNumberJS + retView[0] = 0x00; + } + + return retBuf; + } + + bigInt *= Math.pow(2, 8); + } + + return new ArrayBuffer(0); +} +//************************************************************************************** +// noinspection FunctionWithMultipleReturnPointsJS, ParameterNamingConventionJS +/** + * Compare two array buffers + * @param {!ArrayBuffer} inputBuffer1 + * @param {!ArrayBuffer} inputBuffer2 + * @returns {boolean} + */ +function isEqualBuffer(inputBuffer1, inputBuffer2) { + // noinspection NonBlockStatementBodyJS + if (inputBuffer1.byteLength !== inputBuffer2.byteLength) return false; + + // noinspection LocalVariableNamingConventionJS + const view1 = new Uint8Array(inputBuffer1); + // noinspection LocalVariableNamingConventionJS + const view2 = new Uint8Array(inputBuffer2); + + for (let i = 0; i < view1.length; i++) { + // noinspection NonBlockStatementBodyJS + if (view1[i] !== view2[i]) return false; + } + + return true; +} +//************************************************************************************** +// noinspection FunctionWithMultipleReturnPointsJS +/** + * Pad input number with leade "0" if needed + * @returns {string} + * @param {number} inputNumber + * @param {number} fullLength + */ +function padNumber(inputNumber, fullLength) { + const str = inputNumber.toString(10); + + // noinspection NonBlockStatementBodyJS + if (fullLength < str.length) return ""; + + const dif = fullLength - str.length; + + const padding = new Array(dif); + // noinspection NonBlockStatementBodyJS + for (let i = 0; i < dif; i++) padding[i] = "0"; + + const paddingString = padding.join(""); + + return paddingString.concat(str); +} +//************************************************************************************** +const base64Template = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; +const base64UrlTemplate = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_="; +//************************************************************************************** +// noinspection FunctionWithMultipleLoopsJS, OverlyComplexFunctionJS, FunctionTooLongJS, FunctionNamingConventionJS +/** + * Encode string into BASE64 (or "base64url") + * @param {string} input + * @param {boolean} useUrlTemplate If "true" then output would be encoded using "base64url" + * @param {boolean} skipPadding Skip BASE-64 padding or not + * @param {boolean} skipLeadingZeros Skip leading zeros in input data or not + * @returns {string} + */ +function toBase64(input, useUrlTemplate = false, skipPadding = false, skipLeadingZeros = false) { + let i = 0; + + // noinspection LocalVariableNamingConventionJS + let flag1 = 0; + // noinspection LocalVariableNamingConventionJS + let flag2 = 0; + + let output = ""; + + // noinspection ConditionalExpressionJS + const template = useUrlTemplate ? base64UrlTemplate : base64Template; + + if (skipLeadingZeros) { + let nonZeroPosition = 0; + + for (let i = 0; i < input.length; i++) { + // noinspection ConstantOnRightSideOfComparisonJS + if (input.charCodeAt(i) !== 0) { + nonZeroPosition = i; + // noinspection BreakStatementJS + break; + } + } + + // noinspection AssignmentToFunctionParameterJS + input = input.slice(nonZeroPosition); + } + + while (i < input.length) { + // noinspection LocalVariableNamingConventionJS, IncrementDecrementResultUsedJS + const chr1 = input.charCodeAt(i++); + // noinspection NonBlockStatementBodyJS + if (i >= input.length) flag1 = 1; + // noinspection LocalVariableNamingConventionJS, IncrementDecrementResultUsedJS + const chr2 = input.charCodeAt(i++); + // noinspection NonBlockStatementBodyJS + if (i >= input.length) flag2 = 1; + // noinspection LocalVariableNamingConventionJS, IncrementDecrementResultUsedJS + const chr3 = input.charCodeAt(i++); + + // noinspection LocalVariableNamingConventionJS + const enc1 = chr1 >> 2; + // noinspection LocalVariableNamingConventionJS, MagicNumberJS, NonShortCircuitBooleanExpressionJS + const enc2 = (chr1 & 0x03) << 4 | chr2 >> 4; + // noinspection LocalVariableNamingConventionJS, MagicNumberJS, NonShortCircuitBooleanExpressionJS + let enc3 = (chr2 & 0x0F) << 2 | chr3 >> 6; + // noinspection LocalVariableNamingConventionJS, MagicNumberJS, NonShortCircuitBooleanExpressionJS + let enc4 = chr3 & 0x3F; + + // noinspection ConstantOnRightSideOfComparisonJS + if (flag1 === 1) { + // noinspection NestedAssignmentJS, AssignmentResultUsedJS, MagicNumberJS + enc3 = enc4 = 64; + } else { + // noinspection ConstantOnRightSideOfComparisonJS + if (flag2 === 1) { + // noinspection MagicNumberJS + enc4 = 64; + } + } + + // noinspection NonBlockStatementBodyJS + if (skipPadding) { + // noinspection ConstantOnRightSideOfComparisonJS, NonBlockStatementBodyJS, MagicNumberJS + if (enc3 === 64) output += `${template.charAt(enc1)}${template.charAt(enc2)}`;else { + // noinspection ConstantOnRightSideOfComparisonJS, NonBlockStatementBodyJS, MagicNumberJS + if (enc4 === 64) output += `${template.charAt(enc1)}${template.charAt(enc2)}${template.charAt(enc3)}`;else output += `${template.charAt(enc1)}${template.charAt(enc2)}${template.charAt(enc3)}${template.charAt(enc4)}`; + } + } else output += `${template.charAt(enc1)}${template.charAt(enc2)}${template.charAt(enc3)}${template.charAt(enc4)}`; + } + + return output; +} +//************************************************************************************** +// noinspection FunctionWithMoreThanThreeNegationsJS, FunctionWithMultipleLoopsJS, OverlyComplexFunctionJS, FunctionNamingConventionJS +/** + * Decode string from BASE64 (or "base64url") + * @param {string} input + * @param {boolean} [useUrlTemplate=false] If "true" then output would be encoded using "base64url" + * @param {boolean} [cutTailZeros=false] If "true" then cut tailing zeroz from function result + * @returns {string} + */ +function fromBase64(input, useUrlTemplate = false, cutTailZeros = false) { + // noinspection ConditionalExpressionJS + const template = useUrlTemplate ? base64UrlTemplate : base64Template; + + //region Aux functions + // noinspection FunctionWithMultipleReturnPointsJS, NestedFunctionJS + function indexof(toSearch) { + // noinspection ConstantOnRightSideOfComparisonJS, MagicNumberJS + for (let i = 0; i < 64; i++) { + // noinspection NonBlockStatementBodyJS + if (template.charAt(i) === toSearch) return i; + } + + // noinspection MagicNumberJS + return 64; + } + + // noinspection NestedFunctionJS + function test(incoming) { + // noinspection ConstantOnRightSideOfComparisonJS, ConditionalExpressionJS, MagicNumberJS + return incoming === 64 ? 0x00 : incoming; + } + //endregion + + let i = 0; + + let output = ""; + + while (i < input.length) { + // noinspection NestedFunctionCallJS, LocalVariableNamingConventionJS, IncrementDecrementResultUsedJS + const enc1 = indexof(input.charAt(i++)); + // noinspection NestedFunctionCallJS, LocalVariableNamingConventionJS, ConditionalExpressionJS, MagicNumberJS, IncrementDecrementResultUsedJS + const enc2 = i >= input.length ? 0x00 : indexof(input.charAt(i++)); + // noinspection NestedFunctionCallJS, LocalVariableNamingConventionJS, ConditionalExpressionJS, MagicNumberJS, IncrementDecrementResultUsedJS + const enc3 = i >= input.length ? 0x00 : indexof(input.charAt(i++)); + // noinspection NestedFunctionCallJS, LocalVariableNamingConventionJS, ConditionalExpressionJS, MagicNumberJS, IncrementDecrementResultUsedJS + const enc4 = i >= input.length ? 0x00 : indexof(input.charAt(i++)); + + // noinspection LocalVariableNamingConventionJS, NonShortCircuitBooleanExpressionJS + const chr1 = test(enc1) << 2 | test(enc2) >> 4; + // noinspection LocalVariableNamingConventionJS, MagicNumberJS, NonShortCircuitBooleanExpressionJS + const chr2 = (test(enc2) & 0x0F) << 4 | test(enc3) >> 2; + // noinspection LocalVariableNamingConventionJS, MagicNumberJS, NonShortCircuitBooleanExpressionJS + const chr3 = (test(enc3) & 0x03) << 6 | test(enc4); + + output += String.fromCharCode(chr1); + + // noinspection ConstantOnRightSideOfComparisonJS, NonBlockStatementBodyJS, MagicNumberJS + if (enc3 !== 64) output += String.fromCharCode(chr2); + + // noinspection ConstantOnRightSideOfComparisonJS, NonBlockStatementBodyJS, MagicNumberJS + if (enc4 !== 64) output += String.fromCharCode(chr3); + } + + if (cutTailZeros) { + const outputLength = output.length; + let nonZeroStart = -1; + + // noinspection ConstantOnRightSideOfComparisonJS + for (let i = outputLength - 1; i >= 0; i--) { + // noinspection ConstantOnRightSideOfComparisonJS + if (output.charCodeAt(i) !== 0) { + nonZeroStart = i; + // noinspection BreakStatementJS + break; + } + } + + // noinspection NonBlockStatementBodyJS, NegatedIfStatementJS + if (nonZeroStart !== -1) output = output.slice(0, nonZeroStart + 1);else output = ""; + } + + return output; +} +//************************************************************************************** +function arrayBufferToString(buffer) { + let resultString = ""; + const view = new Uint8Array(buffer); + + // noinspection NonBlockStatementBodyJS + var _iteratorNormalCompletion6 = true; + var _didIteratorError6 = false; + var _iteratorError6 = undefined; + + try { + for (var _iterator6 = view[Symbol.iterator](), _step6; !(_iteratorNormalCompletion6 = (_step6 = _iterator6.next()).done); _iteratorNormalCompletion6 = true) { + const element = _step6.value; + + resultString += String.fromCharCode(element); + } + } catch (err) { + _didIteratorError6 = true; + _iteratorError6 = err; + } finally { + try { + if (!_iteratorNormalCompletion6 && _iterator6.return) { + _iterator6.return(); + } + } finally { + if (_didIteratorError6) { + throw _iteratorError6; + } + } + } + + return resultString; +} +//************************************************************************************** +function stringToArrayBuffer(str) { + const stringLength = str.length; + + const resultBuffer = new ArrayBuffer(stringLength); + const resultView = new Uint8Array(resultBuffer); + + // noinspection NonBlockStatementBodyJS + for (let i = 0; i < stringLength; i++) resultView[i] = str.charCodeAt(i); + + return resultBuffer; +} +//************************************************************************************** +const log2 = Math.log(2); +//************************************************************************************** +// noinspection FunctionNamingConventionJS +/** + * Get nearest to input length power of 2 + * @param {number} length Current length of existing array + * @returns {number} + */ +function nearestPowerOf2(length) { + const base = Math.log(length) / log2; + + const floor = Math.floor(base); + const round = Math.round(base); + + // noinspection ConditionalExpressionJS + return floor === round ? floor : round; +} +//************************************************************************************** +/** + * Delete properties by name from specified object + * @param {Object} object Object to delete properties from + * @param {Array.} propsArray Array of properties names + */ +function clearProps(object, propsArray) { + var _iteratorNormalCompletion7 = true; + var _didIteratorError7 = false; + var _iteratorError7 = undefined; + + try { + for (var _iterator7 = propsArray[Symbol.iterator](), _step7; !(_iteratorNormalCompletion7 = (_step7 = _iterator7.next()).done); _iteratorNormalCompletion7 = true) { + const prop = _step7.value; + + delete object[prop]; + } + } catch (err) { + _didIteratorError7 = true; + _iteratorError7 = err; + } finally { + try { + if (!_iteratorNormalCompletion7 && _iterator7.return) { + _iterator7.return(); + } + } finally { + if (_didIteratorError7) { + throw _iteratorError7; + } + } + } +} +//************************************************************************************** + +},{}]},{},[1])(1) +}); diff --git a/toolkit/components/certviewer/content/vendor/pkijs_bundle.js b/toolkit/components/certviewer/content/vendor/pkijs_bundle.js new file mode 100644 index 000000000000..e9810643b9c5 --- /dev/null +++ b/toolkit/components/certviewer/content/vendor/pkijs_bundle.js @@ -0,0 +1,46647 @@ +(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.pkijs = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i. + * + */ +//************************************************************************************** +class ByteStream { + //********************************************************************************** + // noinspection FunctionWithMultipleLoopsJS + /** + * Constructor for ByteStream class + * @param {{[length]: number, [stub]: number, [view]: Uint8Array, [buffer]: ArrayBuffer, [string]: string, [hexstring]: string}} parameters + */ + constructor(parameters = {}) { + this.clear(); + + var _iteratorNormalCompletion = true; + var _didIteratorError = false; + var _iteratorError = undefined; + + try { + for (var _iterator = Object.keys(parameters)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { + const key = _step.value; + + switch (key) { + case "length": + this.length = parameters.length; + break; + case "stub": + // noinspection NonBlockStatementBodyJS + for (let i = 0; i < this._view.length; i++) this._view[i] = parameters.stub; + break; + case "view": + this.fromUint8Array(parameters.view); + break; + case "buffer": + this.fromArrayBuffer(parameters.buffer); + break; + case "string": + this.fromString(parameters.string); + break; + case "hexstring": + this.fromHexString(parameters.hexstring); + break; + default: + } + } + } catch (err) { + _didIteratorError = true; + _iteratorError = err; + } finally { + try { + if (!_iteratorNormalCompletion && _iterator.return) { + _iterator.return(); + } + } finally { + if (_didIteratorError) { + throw _iteratorError; + } + } + } + } + //********************************************************************************** + /** + * Setter for "buffer" + * @param {ArrayBuffer} value + */ + set buffer(value) { + this._buffer = value.slice(0); + this._view = new Uint8Array(this._buffer); + } + //********************************************************************************** + /** + * Getter for "buffer" + * @returns {ArrayBuffer} + */ + get buffer() { + return this._buffer; + } + //********************************************************************************** + /** + * Setter for "view" + * @param {Uint8Array} value + */ + set view(value) { + this._buffer = new ArrayBuffer(value.length); + this._view = new Uint8Array(this._buffer); + + this._view.set(value); + } + //********************************************************************************** + /** + * Getter for "view" + * @returns {Uint8Array} + */ + get view() { + return this._view; + } + //********************************************************************************** + /** + * Getter for "length" + * @returns {number} + */ + get length() { + return this._buffer.byteLength; + } + //********************************************************************************** + /** + * Setter for "length" + * @param {number} value + */ + set length(value) { + this._buffer = new ArrayBuffer(value); + this._view = new Uint8Array(this._buffer); + } + //********************************************************************************** + /** + * Clear existing stream + */ + clear() { + this._buffer = new ArrayBuffer(0); + this._view = new Uint8Array(this._buffer); + } + //********************************************************************************** + /** + * Initialize "Stream" object from existing "ArrayBuffer" + * @param {!ArrayBuffer} array The ArrayBuffer to copy from + */ + fromArrayBuffer(array) { + this.buffer = array; + } + //********************************************************************************** + // noinspection FunctionNamingConventionJS + /** + * Initialize "Stream" object from existing "Uint8Array" + * @param {!Uint8Array} array The Uint8Array to copy from + */ + fromUint8Array(array) { + this._buffer = new ArrayBuffer(array.length); + this._view = new Uint8Array(this._buffer); + + this._view.set(array); + } + //********************************************************************************** + /** + * Initialize "Stream" object from existing string + * @param {string} string The string to initialize from + */ + fromString(string) { + const stringLength = string.length; + + this.length = stringLength; + + // noinspection NonBlockStatementBodyJS + for (let i = 0; i < stringLength; i++) this.view[i] = string.charCodeAt(i); + } + //********************************************************************************** + /** + * Represent "Stream" object content as a string + * @param {number} [start] Start position to convert to string + * @param {number} [length] Length of array to convert to string + * @returns {string} + */ + toString(start = 0, length = this.view.length - start) { + //region Initial variables + let result = ""; + //endregion + + //region Check input parameters + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if (start >= this.view.length || start < 0) { + // noinspection AssignmentToFunctionParameterJS + start = 0; + } + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if (length >= this.view.length || length < 0) { + // noinspection AssignmentToFunctionParameterJS + length = this.view.length - start; + } + //endregion + + //region Convert array of bytes to string + // noinspection NonBlockStatementBodyJS + for (let i = start; i < start + length; i++) result += String.fromCharCode(this.view[i]); + //endregion + + return result; + } + //********************************************************************************** + // noinspection FunctionTooLongJS + /** + * Initialize "Stream" object from existing hexdecimal string + * @param {string} hexString String to initialize from + */ + fromHexString(hexString) { + //region Initial variables + const stringLength = hexString.length; + + this.buffer = new ArrayBuffer(stringLength >> 1); + this.view = new Uint8Array(this.buffer); + + const hexMap = new Map(); + + // noinspection MagicNumberJS + hexMap.set("0", 0x00); + // noinspection MagicNumberJS + hexMap.set("1", 0x01); + // noinspection MagicNumberJS + hexMap.set("2", 0x02); + // noinspection MagicNumberJS + hexMap.set("3", 0x03); + // noinspection MagicNumberJS + hexMap.set("4", 0x04); + // noinspection MagicNumberJS + hexMap.set("5", 0x05); + // noinspection MagicNumberJS + hexMap.set("6", 0x06); + // noinspection MagicNumberJS + hexMap.set("7", 0x07); + // noinspection MagicNumberJS + hexMap.set("8", 0x08); + // noinspection MagicNumberJS + hexMap.set("9", 0x09); + // noinspection MagicNumberJS + hexMap.set("A", 0x0A); + // noinspection MagicNumberJS + hexMap.set("a", 0x0A); + // noinspection MagicNumberJS + hexMap.set("B", 0x0B); + // noinspection MagicNumberJS + hexMap.set("b", 0x0B); + // noinspection MagicNumberJS + hexMap.set("C", 0x0C); + // noinspection MagicNumberJS + hexMap.set("c", 0x0C); + // noinspection MagicNumberJS + hexMap.set("D", 0x0D); + // noinspection MagicNumberJS + hexMap.set("d", 0x0D); + // noinspection MagicNumberJS + hexMap.set("E", 0x0E); + // noinspection MagicNumberJS + hexMap.set("e", 0x0E); + // noinspection MagicNumberJS + hexMap.set("F", 0x0F); + // noinspection MagicNumberJS + hexMap.set("f", 0x0F); + + let j = 0; + // noinspection MagicNumberJS + let temp = 0x00; + //endregion + + //region Convert char-by-char + for (let i = 0; i < stringLength; i++) { + // noinspection NegatedIfStatementJS + if (!(i % 2)) { + // noinspection NestedFunctionCallJS + temp = hexMap.get(hexString.charAt(i)) << 4; + } else { + // noinspection NestedFunctionCallJS + temp |= hexMap.get(hexString.charAt(i)); + + this.view[j] = temp; + j++; + } + } + //endregion + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols + /** + * Represent "Stream" object content as a hexdecimal string + * @param {number} [start=0] Start position to convert to string + * @param {number} [length=(this.view.length - start)] Length of array to convert to string + * @returns {string} + */ + toHexString(start = 0, length = this.view.length - start) { + //region Initial variables + let result = ""; + //endregion + + //region Check input parameters + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if (start >= this.view.length || start < 0) { + // noinspection AssignmentToFunctionParameterJS + start = 0; + } + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if (length >= this.view.length || length < 0) { + // noinspection AssignmentToFunctionParameterJS + length = this.view.length - start; + } + //endregion + + for (let i = start; i < start + length; i++) { + // noinspection ChainedFunctionCallJS + const str = this.view[i].toString(16).toUpperCase(); + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, ConditionalExpressionJS, EqualityComparisonWithCoercionJS + result = result + (str.length == 1 ? "0" : "") + str; + } + + return result; + } + //********************************************************************************** + // noinspection FunctionWithMultipleReturnPointsJS + /** + * Return copy of existing "Stream" + * @param {number} [start=0] Start position of the copy + * @param {number} [length=this.view.length] Length of the copy + * @returns {ByteStream} + */ + copy(start = 0, length = this._buffer.byteLength - start) { + //region Check input parameters + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, NonBlockStatementBodyJS + if (start === 0 && this._buffer.byteLength === 0) return new ByteStream(); + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, NonBlockStatementBodyJS + if (start < 0 || start > this._buffer.byteLength - 1) throw new Error(`Wrong start position: ${start}`); + //endregion + + const stream = new ByteStream(); + + stream._buffer = this._buffer.slice(start, start + length); + stream._view = new Uint8Array(stream._buffer); + + return stream; + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols, FunctionWithMultipleReturnPointsJS + /** + * Return slice of existing "Stream" + * @param {number} [start=0] Start position of the slice + * @param {number} [end=this._buffer.byteLength] End position of the slice + * @returns {ByteStream} + */ + slice(start = 0, end = this._buffer.byteLength) { + //region Check input parameters + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, NonBlockStatementBodyJS + if (start === 0 && this._buffer.byteLength === 0) return new ByteStream(); + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, NonBlockStatementBodyJS + if (start < 0 || start > this._buffer.byteLength - 1) throw new Error(`Wrong start position: ${start}`); + //endregion + + const stream = new ByteStream(); + + stream._buffer = this._buffer.slice(start, end); + stream._view = new Uint8Array(stream._buffer); + + return stream; + } + //********************************************************************************** + /** + * Change size of existing "Stream" + * @param {!number} size Size for new "Stream" + */ + realloc(size) { + //region Initial variables + const buffer = new ArrayBuffer(size); + const view = new Uint8Array(buffer); + //endregion + + //region Create a new ArrayBuffer content + // noinspection NonBlockStatementBodyJS + if (size > this._view.length) view.set(this._view);else { + // noinspection NestedFunctionCallJS + view.set(new Uint8Array(this._buffer, 0, size)); + } + //endregion + + //region Initialize "Stream" with new "ArrayBuffer" + this._buffer = buffer.slice(0); + this._view = new Uint8Array(this._buffer); + //endregion + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols + /** + * Append a new "Stream" content to the current "Stream" + * @param {ByteStream} stream A new "stream" to append to current "stream" + */ + append(stream) { + //region Initial variables + const initialSize = this._buffer.byteLength; + const streamViewLength = stream._buffer.byteLength; + + const copyView = stream._view.slice(); + //endregion + + //region Re-allocate current internal buffer + this.realloc(initialSize + streamViewLength); + //endregion + + //region Copy input stream content to a new place + this._view.set(copyView, initialSize); + //endregion + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols, FunctionWithMultipleReturnPointsJS + /** + * Insert "Stream" content to the current "Stream" at specific position + * @param {ByteStream} stream A new "stream" to insert to current "stream" + * @param {number} [start=0] Start position to insert to + * @param {number} [length] + * @returns {boolean} + */ + insert(stream, start = 0, length = this._buffer.byteLength - start) { + //region Initial variables + // noinspection NonBlockStatementBodyJS + if (start > this._buffer.byteLength - 1) return false; + + if (length > this._buffer.byteLength - start) { + // noinspection AssignmentToFunctionParameterJS + length = this._buffer.byteLength - start; + } + //endregion + + //region Check input variables + if (length > stream._buffer.byteLength) { + // noinspection AssignmentToFunctionParameterJS + length = stream._buffer.byteLength; + } + //endregion + + //region Update content of the current stream + // noinspection NonBlockStatementBodyJS, EqualityComparisonWithCoercionJS + if (length == stream._buffer.byteLength) this._view.set(stream._view, start);else { + // noinspection NestedFunctionCallJS + this._view.set(stream._view.slice(0, length), start); + } + //endregion + + return true; + } + //********************************************************************************** + // noinspection FunctionWithMultipleReturnPointsJS + /** + * Check that two "Stream" objects has equal content + * @param {ByteStream} stream Stream to compare with + * @returns {boolean} + */ + isEqual(stream) { + //region Check length of both buffers + // noinspection NonBlockStatementBodyJS, EqualityComparisonWithCoercionJS + if (this._buffer.byteLength != stream._buffer.byteLength) return false; + //endregion + + //region Compare each byte of both buffers + for (let i = 0; i < stream._buffer.byteLength; i++) { + // noinspection NonBlockStatementBodyJS, EqualityComparisonWithCoercionJS + if (this.view[i] != stream.view[i]) return false; + } + //endregion + + return true; + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols, FunctionWithMultipleReturnPointsJS + /** + * Check that current "Stream" objects has equal content with input "Uint8Array" + * @param {Uint8Array} view View to compare with + * @returns {boolean} + */ + isEqualView(view) { + //region Check length of both buffers + // noinspection NonBlockStatementBodyJS, EqualityComparisonWithCoercionJS + if (view.length != this.view.length) return false; + //endregion + + //region Compare each byte of both buffers + for (let i = 0; i < view.length; i++) { + // noinspection NonBlockStatementBodyJS, EqualityComparisonWithCoercionJS + if (this.view[i] != view[i]) return false; + } + //endregion + + return true; + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols, FunctionWithMultipleLoopsJS, FunctionWithMultipleReturnPointsJS, OverlyComplexFunctionJS, FunctionTooLongJS + /** + * Find any byte pattern in "Stream" + * @param {ByteStream} pattern Stream having pattern value + * @param {?number} [start] Start position to search from + * @param {?number} [length] Length of byte block to search at + * @param {boolean} [backward] Flag to search in backward order + * @returns {number} + */ + findPattern(pattern, start = null, length = null, backward = false) { + //region Check input variables + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if (start == null) { + // noinspection AssignmentToFunctionParameterJS, ConditionalExpressionJS + start = backward ? this.buffer.byteLength : 0; + } + + if (start > this.buffer.byteLength) { + // noinspection AssignmentToFunctionParameterJS + start = this.buffer.byteLength; + } + + if (backward) { + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if (length == null) { + // noinspection AssignmentToFunctionParameterJS + length = start; + } + + if (length > start) { + // noinspection AssignmentToFunctionParameterJS + length = start; + } + } else { + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if (length == null) { + // noinspection AssignmentToFunctionParameterJS + length = this.buffer.byteLength - start; + } + + if (length > this.buffer.byteLength - start) { + // noinspection AssignmentToFunctionParameterJS + length = this.buffer.byteLength - start; + } + } + //endregion + + //region Initial variables + const patternLength = pattern.buffer.byteLength; + // noinspection NonBlockStatementBodyJS + if (patternLength > length) return -1; + //endregion + + //region Make a "pre-read" array for pattern + const patternArray = []; + // noinspection NonBlockStatementBodyJS + for (let i = 0; i < patternLength; i++) patternArray.push(pattern.view[i]); + //endregion + + //region Search for pattern + for (let i = 0; i <= length - patternLength; i++) { + let equal = true; + // noinspection ConditionalExpressionJS + const equalStart = backward ? start - patternLength - i : start + i; + + for (let j = 0; j < patternLength; j++) { + // noinspection EqualityComparisonWithCoercionJS + if (this.view[j + equalStart] != patternArray[j]) { + equal = false; + // noinspection BreakStatementJS + break; + } + } + + if (equal) { + // noinspection ConditionalExpressionJS + return backward ? start - patternLength - i : start + patternLength + i; // Position after the pattern found + } + } + //endregion + + return -1; + } + //********************************************************************************** + // noinspection OverlyComplexFunctionJS + /** + * Find first position of any pattern from input array + * @param {Array.} patterns Array with patterns which should be found + * @param {?number} [start] Start position to search from + * @param {?number} [length] Length of byte block to search at + * @param {boolean} [backward=false] Flag to search in backward order + * @returns {{id: number, position: number}} + */ + findFirstIn(patterns, start = null, length = null, backward = false) { + //region Initial variables + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if (start == null) { + // noinspection AssignmentToFunctionParameterJS, ConditionalExpressionJS + start = backward ? this.buffer.byteLength : 0; + } + + if (start > this.buffer.byteLength) { + // noinspection AssignmentToFunctionParameterJS + start = this.buffer.byteLength; + } + + if (backward) { + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if (length == null) { + // noinspection AssignmentToFunctionParameterJS + length = start; + } + + if (length > start) { + // noinspection AssignmentToFunctionParameterJS + length = start; + } + } else { + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if (length == null) { + // noinspection AssignmentToFunctionParameterJS + length = this.buffer.byteLength - start; + } + + if (length > this.buffer.byteLength - start) { + // noinspection AssignmentToFunctionParameterJS + length = this.buffer.byteLength - start; + } + } + + // noinspection ConditionalExpressionJS + const result = { + id: -1, + position: backward ? 0 : start + length, + length: 0 + }; + //endregion + + for (let i = 0; i < patterns.length; i++) { + const position = this.findPattern(patterns[i], start, length, backward); + // noinspection EqualityComparisonWithCoercionJS + if (position != -1) { + let valid = false; + const patternLength = patterns[i].length; + + if (backward) { + // noinspection NonBlockStatementBodyJS + if (position - patternLength >= result.position - result.length) valid = true; + } else { + // noinspection NonBlockStatementBodyJS + if (position - patternLength <= result.position - result.length) valid = true; + } + + if (valid) { + result.position = position; + result.id = i; + result.length = patternLength; + } + } + } + + return result; + } + //********************************************************************************** + // noinspection FunctionWithMultipleReturnPointsJS + /** + * Find all positions of any pattern from input array + * @param {Array.} patterns Array with patterns which should be found + * @param {?number} [start] Start position to search from + * @param {?number} [length] Length of byte block to search at + * @returns {Array} + */ + findAllIn(patterns, start = 0, length = this.buffer.byteLength - start) { + //region Initial variables + const result = []; + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if (start == null) { + // noinspection AssignmentToFunctionParameterJS + start = 0; + } + + // noinspection NonBlockStatementBodyJS + if (start > this.buffer.byteLength - 1) return result; + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if (length == null) { + // noinspection AssignmentToFunctionParameterJS + length = this.buffer.byteLength - start; + } + + if (length > this.buffer.byteLength - start) { + // noinspection AssignmentToFunctionParameterJS + length = this.buffer.byteLength - start; + } + + let patternFound = { + id: -1, + position: start + }; + //endregion + + //region Find all accurences of patterns + do { + const position = patternFound.position; + + patternFound = this.findFirstIn(patterns, patternFound.position, length); + + // noinspection EqualityComparisonWithCoercionJS + if (patternFound.id == -1) { + // noinspection BreakStatementJS + break; + } + + // noinspection AssignmentToFunctionParameterJS + length -= patternFound.position - position; + + result.push({ + id: patternFound.id, + position: patternFound.position + }); + } while (true); // eslint-disable-line + //endregion + + return result; + } + //********************************************************************************** + // noinspection FunctionWithMultipleLoopsJS, FunctionWithMultipleReturnPointsJS + /** + * Find all positions of a pattern + * @param {ByteStream} pattern Stream having pattern value + * @param {?number} [start] Start position to search from + * @param {?number} [length] Length of byte block to search at + * @returns {Array|number} Array with all pattern positions or (-1) if failed + */ + findAllPatternIn(pattern, start = 0, length = this.buffer.byteLength - start) { + //region Check input variables + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if (start == null) { + // noinspection AssignmentToFunctionParameterJS + start = 0; + } + + if (start > this.buffer.byteLength) { + // noinspection AssignmentToFunctionParameterJS + start = this.buffer.byteLength; + } + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if (length == null) { + // noinspection AssignmentToFunctionParameterJS + length = this.buffer.byteLength - start; + } + + if (length > this.buffer.byteLength - start) { + // noinspection AssignmentToFunctionParameterJS + length = this.buffer.byteLength - start; + } + //endregion + + //region Initial variables + const result = []; + + const patternLength = pattern.buffer.byteLength; + // noinspection NonBlockStatementBodyJS + if (patternLength > length) return -1; + //endregion + + //region Make a "pre-read" array for pattern + const patternArray = Array.from(pattern.view); + //endregion + + //region Search for pattern + for (let i = 0; i <= length - patternLength; i++) { + let equal = true; + const equalStart = start + i; + + for (let j = 0; j < patternLength; j++) { + // noinspection EqualityComparisonWithCoercionJS + if (this.view[j + equalStart] != patternArray[j]) { + equal = false; + // noinspection BreakStatementJS + break; + } + } + + if (equal) { + result.push(start + patternLength + i); // Position after the pattern found + i += patternLength - 1; // On next step of "for" we will have "i++" + } + } + //endregion + + return result; + } + //********************************************************************************** + // noinspection OverlyComplexFunctionJS, FunctionTooLongJS + /** + * Find first position of data, not included in patterns from input array + * @param {Array.} patterns Array with patterns which should be ommited + * @param {?number} [start] Start position to search from + * @param {?number} [length] Length of byte block to search at + * @param {boolean} [backward=false] Flag to search in backward order + * @returns {{left: {id: number, position: *}, right: {id: number, position: number}, value: ByteStream}} + */ + findFirstNotIn(patterns, start = null, length = null, backward = false) { + //region Initial variables + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if (start == null) { + // noinspection AssignmentToFunctionParameterJS, ConditionalExpressionJS + start = backward ? this.buffer.byteLength : 0; + } + + if (start > this.buffer.byteLength) { + // noinspection AssignmentToFunctionParameterJS + start = this.buffer.byteLength; + } + + if (backward) { + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if (length == null) { + // noinspection AssignmentToFunctionParameterJS + length = start; + } + + if (length > start) { + // noinspection AssignmentToFunctionParameterJS + length = start; + } + } else { + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if (length == null) { + // noinspection AssignmentToFunctionParameterJS + length = this.buffer.byteLength - start; + } + + if (length > this.buffer.byteLength - start) { + // noinspection AssignmentToFunctionParameterJS + length = this.buffer.byteLength - start; + } + } + + const result = { + left: { + id: -1, + position: start + }, + right: { + id: -1, + position: 0 + }, + value: new ByteStream() + }; + + let currentLength = length; + //endregion + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + while (currentLength > 0) { + //region Search for nearest "pattern" + // noinspection ConditionalExpressionJS + result.right = this.findFirstIn(patterns, backward ? start - length + currentLength : start + length - currentLength, currentLength, backward); + //endregion + + //region No pattern at all + // noinspection EqualityComparisonWithCoercionJS + if (result.right.id == -1) { + // noinspection AssignmentToFunctionParameterJS + length = currentLength; + + if (backward) { + // noinspection AssignmentToFunctionParameterJS + start -= length; + } else { + // noinspection AssignmentToFunctionParameterJS + start = result.left.position; + } + + result.value = new ByteStream(); + + result.value._buffer = this._buffer.slice(start, start + length); + result.value._view = new Uint8Array(result.value._buffer); + + // noinspection BreakStatementJS + break; + } + //endregion + + //region Check distance between two patterns + // noinspection ConditionalExpressionJS, EqualityComparisonWithCoercionJS + if (result.right.position != (backward ? result.left.position - patterns[result.right.id].buffer.byteLength : result.left.position + patterns[result.right.id].buffer.byteLength)) { + if (backward) { + // noinspection AssignmentToFunctionParameterJS + start = result.right.position + patterns[result.right.id].buffer.byteLength; + // noinspection AssignmentToFunctionParameterJS + length = result.left.position - result.right.position - patterns[result.right.id].buffer.byteLength; + } else { + // noinspection AssignmentToFunctionParameterJS + start = result.left.position; + // noinspection AssignmentToFunctionParameterJS + length = result.right.position - result.left.position - patterns[result.right.id].buffer.byteLength; + } + + result.value = new ByteStream(); + + result.value._buffer = this._buffer.slice(start, start + length); + result.value._view = new Uint8Array(result.value._buffer); + + // noinspection BreakStatementJS + break; + } + //endregion + + //region Store information about previous pattern + result.left = result.right; + //endregion + + //region Change current length + currentLength -= patterns[result.right.id]._buffer.byteLength; + //endregion + } + + //region Swap "patterns" in case of backward order + if (backward) { + const temp = result.right; + result.right = result.left; + result.left = temp; + } + //endregion + + return result; + } + //********************************************************************************** + // noinspection FunctionWithMultipleReturnPointsJS + /** + * Find all positions of data, not included in patterns from input array + * @param {Array.} patterns Array with patterns which should be ommited + * @param {?number} [start] Start position to search from + * @param {?number} [length] Length of byte block to search at + * @returns {Array} + */ + findAllNotIn(patterns, start = null, length = null) { + //region Initial variables + const result = []; + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if (start == null) { + // noinspection AssignmentToFunctionParameterJS + start = 0; + } + + // noinspection NonBlockStatementBodyJS + if (start > this.buffer.byteLength - 1) return result; + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if (length == null) { + // noinspection AssignmentToFunctionParameterJS + length = this.buffer.byteLength - start; + } + + if (length > this.buffer.byteLength - start) { + // noinspection AssignmentToFunctionParameterJS + length = this.buffer.byteLength - start; + } + + let patternFound = { + left: { + id: -1, + position: start + }, + right: { + id: -1, + position: start + }, + value: new ByteStream() + }; + //endregion + + //region Find all accurences of patterns + // noinspection EqualityComparisonWithCoercionJS + do { + const position = patternFound.right.position; + + patternFound = this.findFirstNotIn(patterns, patternFound.right.position, length); + + // noinspection AssignmentToFunctionParameterJS + length -= patternFound.right.position - position; + + result.push({ + left: { + id: patternFound.left.id, + position: patternFound.left.position + }, + right: { + id: patternFound.right.id, + position: patternFound.right.position + }, + value: patternFound.value + }); + } while (patternFound.right.id != -1); + //endregion + + return result; + } + //********************************************************************************** + // noinspection FunctionWithMultipleReturnPointsJS, OverlyComplexFunctionJS + /** + * Find position of a sequence of any patterns from input array + * @param {Array.} patterns Array of pattern to look for + * @param {?number} [start] Start position to search from + * @param {?number} [length] Length of byte block to search at + * @param {boolean} [backward=false] Flag to search in backward order + * @returns {*} + */ + findFirstSequence(patterns, start = null, length = null, backward = false) { + //region Initial variables + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if (start == null) { + // noinspection AssignmentToFunctionParameterJS, ConditionalExpressionJS + start = backward ? this.buffer.byteLength : 0; + } + + if (start > this.buffer.byteLength) { + // noinspection AssignmentToFunctionParameterJS + start = this.buffer.byteLength; + } + + if (backward) { + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if (length == null) { + // noinspection AssignmentToFunctionParameterJS + length = start; + } + + if (length > start) { + // noinspection AssignmentToFunctionParameterJS + length = start; + } + } else { + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if (length == null) { + // noinspection AssignmentToFunctionParameterJS + length = this.buffer.byteLength - start; + } + + if (length > this.buffer.byteLength - start) { + // noinspection AssignmentToFunctionParameterJS + length = this.buffer.byteLength - start; + } + } + //endregion + + //region Find first byte from sequence + const firstIn = this.skipNotPatterns(patterns, start, length, backward); + // noinspection EqualityComparisonWithCoercionJS + if (firstIn == -1) { + return { + position: -1, + value: new ByteStream() + }; + } + //endregion + + //region Find first byte not in sequence + // noinspection ConditionalExpressionJS + const firstNotIn = this.skipPatterns(patterns, firstIn, length - (backward ? start - firstIn : firstIn - start), backward); + //endregion + + //region Make output value + if (backward) { + // noinspection AssignmentToFunctionParameterJS + start = firstNotIn; + // noinspection AssignmentToFunctionParameterJS + length = firstIn - firstNotIn; + } else { + // noinspection AssignmentToFunctionParameterJS + start = firstIn; + // noinspection AssignmentToFunctionParameterJS + length = firstNotIn - firstIn; + } + + const value = new ByteStream(); + + value._buffer = this._buffer.slice(start, start + length); + value._view = new Uint8Array(value._buffer); + //endregion + + return { + position: firstNotIn, + value + }; + } + //********************************************************************************** + // noinspection FunctionWithMultipleReturnPointsJS + /** + * Find all positions of a sequence of any patterns from input array + * @param {Array.} patterns Array of patterns to search for + * @param {?number} [start] Start position to search from + * @param {?number} [length] Length of byte block to search at + * @returns {Array} + */ + findAllSequences(patterns, start = null, length = null) { + //region Initial variables + const result = []; + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if (start == null) { + // noinspection AssignmentToFunctionParameterJS + start = 0; + } + + // noinspection NonBlockStatementBodyJS + if (start > this.buffer.byteLength - 1) return result; + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if (length == null) { + // noinspection AssignmentToFunctionParameterJS + length = this.buffer.byteLength - start; + } + + if (length > this.buffer.byteLength - start) { + // noinspection AssignmentToFunctionParameterJS + length = this.buffer.byteLength - start; + } + + let patternFound = { + position: start, + value: new ByteStream() + }; + //endregion + + //region Find all accurences of patterns + // noinspection EqualityComparisonWithCoercionJS + do { + const position = patternFound.position; + + patternFound = this.findFirstSequence(patterns, patternFound.position, length); + + // noinspection EqualityComparisonWithCoercionJS + if (patternFound.position != -1) { + // noinspection AssignmentToFunctionParameterJS + length -= patternFound.position - position; + + result.push({ + position: patternFound.position, + value: patternFound.value + }); + } + } while (patternFound.position != -1); + //endregion + + return result; + } + //********************************************************************************** + // noinspection FunctionWithMultipleLoopsJS, FunctionWithMultipleReturnPointsJS, OverlyComplexFunctionJS, FunctionTooLongJS + /** + * Find all paired patterns in the stream + * @param {ByteStream} leftPattern Left pattern to search for + * @param {ByteStream} rightPattern Right pattern to search for + * @param {?number} [start=null] Start position to search from + * @param {?number} [length=null] Length of byte block to search at + * @returns {Array} + */ + findPairedPatterns(leftPattern, rightPattern, start = null, length = null) { + //region Initial variables + const result = []; + + // noinspection NonBlockStatementBodyJS + if (leftPattern.isEqual(rightPattern)) return result; + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if (start == null) { + // noinspection AssignmentToFunctionParameterJS + start = 0; + } + + // noinspection NonBlockStatementBodyJS + if (start > this.buffer.byteLength - 1) return result; + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if (length == null) { + // noinspection AssignmentToFunctionParameterJS + length = this.buffer.byteLength - start; + } + + if (length > this.buffer.byteLength - start) { + // noinspection AssignmentToFunctionParameterJS + length = this.buffer.byteLength - start; + } + + let currentPositionLeft = 0; + //endregion + + //region Find all "left patterns" as sorted array + const leftPatterns = this.findAllPatternIn(leftPattern, start, length); + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, NonBlockStatementBodyJS, EqualityComparisonWithCoercionJS + if (leftPatterns.length == 0) return result; + //endregion + + //region Find all "right patterns" as sorted array + const rightPatterns = this.findAllPatternIn(rightPattern, start, length); + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, NonBlockStatementBodyJS, EqualityComparisonWithCoercionJS + if (rightPatterns.length == 0) return result; + //endregion + + //region Combine patterns + while (currentPositionLeft < leftPatterns.length) { + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, EqualityComparisonWithCoercionJS + if (rightPatterns.length == 0) { + // noinspection BreakStatementJS + break; + } + + // noinspection EqualityComparisonWithCoercionJS + if (leftPatterns[0] == rightPatterns[0]) { + // Possible situation when one pattern is a part of another + // For example "stream" and "endstream" + // In case when we have only "endstream" in fact "stream" will be also found at the same position + // (position of the pattern is an index AFTER the pattern) + + result.push({ + left: leftPatterns[0], + right: rightPatterns[0] + }); + + leftPatterns.splice(0, 1); + rightPatterns.splice(0, 1); + + // noinspection ContinueStatementJS + continue; + } + + if (leftPatterns[currentPositionLeft] > rightPatterns[0]) { + // noinspection BreakStatementJS + break; + } + + while (leftPatterns[currentPositionLeft] < rightPatterns[0]) { + currentPositionLeft++; + + if (currentPositionLeft >= leftPatterns.length) { + // noinspection BreakStatementJS + break; + } + } + + result.push({ + left: leftPatterns[currentPositionLeft - 1], + right: rightPatterns[0] + }); + + leftPatterns.splice(currentPositionLeft - 1, 1); + rightPatterns.splice(0, 1); + + currentPositionLeft = 0; + } + //endregion + + //region Sort result + result.sort((a, b) => a.left - b.left); + //endregion + + return result; + } + //********************************************************************************** + // noinspection FunctionWithMultipleLoopsJS, FunctionWithMultipleReturnPointsJS, OverlyComplexFunctionJS, FunctionTooLongJS + /** + * Find all paired patterns in the stream + * @param {Array.} inputLeftPatterns Array of left patterns to search for + * @param {Array.} inputRightPatterns Array of right patterns to search for + * @param {?number} [start=null] Start position to search from + * @param {?number} [length=null] Length of byte block to search at + * @returns {Array} + */ + findPairedArrays(inputLeftPatterns, inputRightPatterns, start = null, length = null) { + //region Initial variables + const result = []; + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if (start == null) { + // noinspection AssignmentToFunctionParameterJS + start = 0; + } + + // noinspection NonBlockStatementBodyJS + if (start > this.buffer.byteLength - 1) return result; + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if (length == null) { + // noinspection AssignmentToFunctionParameterJS + length = this.buffer.byteLength - start; + } + + if (length > this.buffer.byteLength - start) { + // noinspection AssignmentToFunctionParameterJS + length = this.buffer.byteLength - start; + } + + let currentPositionLeft = 0; + //endregion + + //region Find all "left patterns" as sorted array + const leftPatterns = this.findAllIn(inputLeftPatterns, start, length); + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, NonBlockStatementBodyJS, EqualityComparisonWithCoercionJS + if (leftPatterns.length == 0) return result; + //endregion + + //region Find all "right patterns" as sorted array + const rightPatterns = this.findAllIn(inputRightPatterns, start, length); + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, NonBlockStatementBodyJS, EqualityComparisonWithCoercionJS + if (rightPatterns.length == 0) return result; + //endregion + + //region Combine patterns + while (currentPositionLeft < leftPatterns.length) { + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, EqualityComparisonWithCoercionJS + if (rightPatterns.length == 0) { + // noinspection BreakStatementJS + break; + } + + // noinspection EqualityComparisonWithCoercionJS + if (leftPatterns[0].position == rightPatterns[0].position) { + // Possible situation when one pattern is a part of another + // For example "stream" and "endstream" + // In case when we have only "endstream" in fact "stream" will be also found at the same position + // (position of the pattern is an index AFTER the pattern) + + result.push({ + left: leftPatterns[0], + right: rightPatterns[0] + }); + + leftPatterns.splice(0, 1); + rightPatterns.splice(0, 1); + + // noinspection ContinueStatementJS + continue; + } + + if (leftPatterns[currentPositionLeft].position > rightPatterns[0].position) { + // noinspection BreakStatementJS + break; + } + + while (leftPatterns[currentPositionLeft].position < rightPatterns[0].position) { + currentPositionLeft++; + + if (currentPositionLeft >= leftPatterns.length) { + // noinspection BreakStatementJS + break; + } + } + + result.push({ + left: leftPatterns[currentPositionLeft - 1], + right: rightPatterns[0] + }); + + leftPatterns.splice(currentPositionLeft - 1, 1); + rightPatterns.splice(0, 1); + + currentPositionLeft = 0; + } + //endregion + + //region Sort result + result.sort((a, b) => a.left.position - b.left.position); + //endregion + + return result; + } + //********************************************************************************** + // noinspection FunctionWithMultipleReturnPointsJS, FunctionTooLongJS + /** + * Replace one patter with other + * @param {ByteStream} searchPattern The pattern to search for + * @param {ByteStream} replacePattern The pattern to replace initial pattern + * @param {?number} [start=null] Start position to search from + * @param {?number} [length=null] Length of byte block to search at + * @param {Array|null} [findAllResult=null] Pre-calculated results of "findAllIn" + * @returns {*} + */ + replacePattern(searchPattern, replacePattern, start = null, length = null, findAllResult = null) { + //region Initial variables + let result; + + let i; + const output = { + status: -1, + searchPatternPositions: [], + replacePatternPositions: [] + }; + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if (start == null) { + // noinspection AssignmentToFunctionParameterJS + start = 0; + } + + // noinspection NonBlockStatementBodyJS + if (start > this.buffer.byteLength - 1) return false; + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if (length == null) { + // noinspection AssignmentToFunctionParameterJS + length = this.buffer.byteLength - start; + } + + if (length > this.buffer.byteLength - start) { + // noinspection AssignmentToFunctionParameterJS + length = this.buffer.byteLength - start; + } + //endregion + + //region Find a pattern to search for + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, NonBlockStatementBodyJS + if (findAllResult == null) { + result = this.findAllIn([searchPattern], start, length); + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, NonBlockStatementBodyJS, EqualityComparisonWithCoercionJS + if (result.length == 0) return output; + } else result = findAllResult; + + // noinspection NestedFunctionCallJS + output.searchPatternPositions.push(...Array.from(result, element => element.position)); + //endregion + + //region Variables for new buffer initialization + const patternDifference = searchPattern.buffer.byteLength - replacePattern.buffer.byteLength; + + const changedBuffer = new ArrayBuffer(this.view.length - result.length * patternDifference); + const changedView = new Uint8Array(changedBuffer); + //endregion + + //region Copy data from 0 to start + // noinspection NestedFunctionCallJS + changedView.set(new Uint8Array(this.buffer, 0, start)); + //endregion + + //region Replace pattern + for (i = 0; i < result.length; i++) { + //region Initial variables + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, ConditionalExpressionJS, EqualityComparisonWithCoercionJS + const currentPosition = i == 0 ? start : result[i - 1].position; + //endregion + + //region Copy bytes other then search pattern + // noinspection NestedFunctionCallJS + changedView.set(new Uint8Array(this.buffer, currentPosition, result[i].position - searchPattern.buffer.byteLength - currentPosition), currentPosition - i * patternDifference); + //endregion + + //region Put replace pattern in a new buffer + changedView.set(replacePattern.view, result[i].position - searchPattern.buffer.byteLength - i * patternDifference); + + output.replacePatternPositions.push(result[i].position - searchPattern.buffer.byteLength - i * patternDifference); + //endregion + } + //endregion + + //region Copy data from the end of old buffer + i--; + // noinspection NestedFunctionCallJS + changedView.set(new Uint8Array(this.buffer, result[i].position, this.buffer.byteLength - result[i].position), result[i].position - searchPattern.buffer.byteLength + replacePattern.buffer.byteLength - i * patternDifference); + //endregion + + //region Re-initialize existing buffer + this.buffer = changedBuffer; + this.view = new Uint8Array(this.buffer); + //endregion + + output.status = 1; + + return output; + } + //********************************************************************************** + // noinspection FunctionWithMultipleLoopsJS, FunctionWithMultipleReturnPointsJS, OverlyComplexFunctionJS, FunctionTooLongJS + /** + * Skip any pattern from input array + * @param {Array.} patterns Array with patterns which should be ommited + * @param {?number} [start=null] Start position to search from + * @param {?number} [length=null] Length of byte block to search at + * @param {boolean} [backward=false] Flag to search in backward order + * @returns {*} + */ + skipPatterns(patterns, start = null, length = null, backward = false) { + //region Initial variables + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if (start == null) { + // noinspection AssignmentToFunctionParameterJS, ConditionalExpressionJS + start = backward ? this.buffer.byteLength : 0; + } + + if (start > this.buffer.byteLength) { + // noinspection AssignmentToFunctionParameterJS + start = this.buffer.byteLength; + } + + if (backward) { + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if (length == null) { + // noinspection AssignmentToFunctionParameterJS + length = start; + } + + if (length > start) { + // noinspection AssignmentToFunctionParameterJS + length = start; + } + } else { + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if (length == null) { + // noinspection AssignmentToFunctionParameterJS + length = this.buffer.byteLength - start; + } + + if (length > this.buffer.byteLength - start) { + // noinspection AssignmentToFunctionParameterJS + length = this.buffer.byteLength - start; + } + } + + let result = start; + //endregion + + //region Search for pattern + for (let k = 0; k < patterns.length; k++) { + const patternLength = patterns[k].buffer.byteLength; + // noinspection ConditionalExpressionJS + const equalStart = backward ? result - patternLength : result; + let equal = true; + + for (let j = 0; j < patternLength; j++) { + // noinspection EqualityComparisonWithCoercionJS + if (this.view[j + equalStart] != patterns[k].view[j]) { + equal = false; + // noinspection BreakStatementJS + break; + } + } + + if (equal) { + k = -1; + + if (backward) { + result -= patternLength; + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, NonBlockStatementBodyJS + if (result <= 0) return result; + } else { + result += patternLength; + // noinspection NonBlockStatementBodyJS + if (result >= start + length) return result; + } + } + } + //endregion + + return result; + } + //********************************************************************************** + // noinspection FunctionWithMultipleLoopsJS, OverlyComplexFunctionJS, FunctionTooLongJS + /** + * Skip any pattern not from input array + * @param {Array.} patterns Array with patterns which should not be ommited + * @param start + * @param length + * @param backward + * @returns {number} + */ + skipNotPatterns(patterns, start = null, length = null, backward = false) { + //region Initial variables + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if (start == null) { + // noinspection AssignmentToFunctionParameterJS, ConditionalExpressionJS + start = backward ? this.buffer.byteLength : 0; + } + + if (start > this.buffer.byteLength) { + // noinspection AssignmentToFunctionParameterJS + start = this.buffer.byteLength; + } + + if (backward) { + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if (length == null) { + // noinspection AssignmentToFunctionParameterJS + length = start; + } + + if (length > start) { + // noinspection AssignmentToFunctionParameterJS + length = start; + } + } else { + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if (length == null) { + // noinspection AssignmentToFunctionParameterJS + length = this.buffer.byteLength - start; + } + + if (length > this.buffer.byteLength - start) { + // noinspection AssignmentToFunctionParameterJS + length = this.buffer.byteLength - start; + } + } + + let result = -1; + //endregion + + //region Search for pattern + for (let i = 0; i < length; i++) { + for (let k = 0; k < patterns.length; k++) { + const patternLength = patterns[k].buffer.byteLength; + // noinspection ConditionalExpressionJS + const equalStart = backward ? start - i - patternLength : start + i; + let equal = true; + + for (let j = 0; j < patternLength; j++) { + // noinspection EqualityComparisonWithCoercionJS + if (this.view[j + equalStart] != patterns[k].view[j]) { + equal = false; + // noinspection BreakStatementJS + break; + } + } + + if (equal) { + // noinspection ConditionalExpressionJS + result = backward ? start - i : start + i; // Exact position of pattern found + // noinspection BreakStatementJS + break; + } + } + + // noinspection EqualityComparisonWithCoercionJS + if (result != -1) { + // noinspection BreakStatementJS + break; + } + } + //endregion + + return result; + } + //********************************************************************************** +} +exports.ByteStream = ByteStream; //************************************************************************************** + +class SeqStream { + //********************************************************************************** + /** + * Constructor for "SeqStream" class + * @param {{[stream]: ByteStream, [length]: number, [backward]: boolean, [start]: number, [appendBlock]: number}} parameters + */ + constructor(parameters = {}) { + /** + * Major stream + * @type {ByteStream} + */ + this.stream = new ByteStream(); + /** + * Length of the major stream + * @type {number} + */ + this._length = 0; + /** + * Flag to search in backward direction + * @type {boolean} + */ + this.backward = false; + /** + * Start position to search + * @type {number} + */ + this._start = 0; + /** + * Length of a block when append information to major stream + * @type {number} + */ + this.appendBlock = 0; + + this.prevLength = 0; + this.prevStart = 0; + + var _iteratorNormalCompletion2 = true; + var _didIteratorError2 = false; + var _iteratorError2 = undefined; + + try { + for (var _iterator2 = Object.keys(parameters)[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { + const key = _step2.value; + + switch (key) { + case "stream": + this.stream = parameters.stream; + break; + case "backward": + this.backward = parameters.backward; + // noinspection JSUnusedGlobalSymbols + this._start = this.stream.buffer.byteLength; + break; + case "length": + // noinspection JSUnusedGlobalSymbols + this._length = parameters.length; + break; + case "start": + // noinspection JSUnusedGlobalSymbols + this._start = parameters.start; + break; + case "appendBlock": + this.appendBlock = parameters.appendBlock; + break; + case "view": + this.stream = new ByteStream({ view: parameters.view }); + break; + case "buffer": + this.stream = new ByteStream({ buffer: parameters.buffer }); + break; + case "string": + this.stream = new ByteStream({ string: parameters.string }); + break; + case "hexstring": + this.stream = new ByteStream({ hexstring: parameters.hexstring }); + break; + default: + } + } + } catch (err) { + _didIteratorError2 = true; + _iteratorError2 = err; + } finally { + try { + if (!_iteratorNormalCompletion2 && _iterator2.return) { + _iterator2.return(); + } + } finally { + if (_didIteratorError2) { + throw _iteratorError2; + } + } + } + } + //********************************************************************************** + /** + * Setter for "stream" property + * @param {ByteStream} value + */ + set stream(value) { + this._stream = value; + + this.prevLength = this._length; + // noinspection JSUnusedGlobalSymbols + this._length = value._buffer.byteLength; + + this.prevStart = this._start; + // noinspection JSUnusedGlobalSymbols + this._start = 0; + } + //********************************************************************************** + /** + * Getter for "stream" property + * @returns {ByteStream} + */ + get stream() { + return this._stream; + } + //********************************************************************************** + /** + * Setter for "length" property + * @param {number} value + */ + set length(value) { + this.prevLength = this._length; + // noinspection JSUnusedGlobalSymbols + this._length = value; + } + //********************************************************************************** + // noinspection FunctionWithMultipleReturnPointsJS + /** + * Getter for "length" property + * @returns {number} + */ + get length() { + // noinspection NonBlockStatementBodyJS + if (this.appendBlock) return this.start; + + return this._length; + } + //********************************************************************************** + // noinspection FunctionWithMultipleReturnPointsJS + /** + * Setter for "start" property + * @param {number} value + */ + set start(value) { + // noinspection NonBlockStatementBodyJS + if (value > this.stream.buffer.byteLength) return; + + //region Initialization of "prev" internal variables + this.prevStart = this._start; + this.prevLength = this._length; + //endregion + + // noinspection JSUnusedGlobalSymbols, ConditionalExpressionJS + this._length -= this.backward ? this._start - value : value - this._start; + // noinspection JSUnusedGlobalSymbols + this._start = value; + } + //********************************************************************************** + /** + * Getter for "start" property + * @returns {number} + */ + get start() { + return this._start; + } + //********************************************************************************** + /** + * Return ArrayBuffer with having value of existing SeqStream length + * @return {ArrayBuffer} + */ + get buffer() { + return this._stream._buffer.slice(0, this._length); + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols + /** + * Reset current position of the "SeqStream" + */ + resetPosition() { + // noinspection JSUnusedGlobalSymbols + this._start = this.prevStart; + // noinspection JSUnusedGlobalSymbols + this._length = this.prevLength; + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols, FunctionWithMultipleReturnPointsJS + /** + * Find any byte pattern in "ByteStream" + * @param {ByteStream} pattern Stream having pattern value + * @param {?number} [gap] Maximum gap between start position and position of nearest object + * @returns {number} + */ + findPattern(pattern, gap = null) { + //region Initial variables + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if (gap == null || gap > this.length) { + // noinspection AssignmentToFunctionParameterJS + gap = this.length; + } + //endregion + + //region Find pattern + const result = this.stream.findPattern(pattern, this.start, this.length, this.backward); + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, NonBlockStatementBodyJS, EqualityComparisonWithCoercionJS + if (result == -1) return result; + + if (this.backward) { + // noinspection NonBlockStatementBodyJS + if (result < this.start - pattern.buffer.byteLength - gap) return -1; + } else { + // noinspection NonBlockStatementBodyJS + if (result > this.start + pattern.buffer.byteLength + gap) return -1; + } + //endregion + + //region Create new values + this.start = result; + //endregion ; + + return result; + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols, FunctionWithMultipleReturnPointsJS + /** + * Find first position of any pattern from input array + * @param {Array.} patterns Array with patterns which should be found + * @param {?number} [gap] Maximum gap between start position and position of nearest object + * @returns {{id: number, position: number}} + */ + findFirstIn(patterns, gap = null) { + //region Initial variables + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if (gap == null || gap > this.length) { + // noinspection AssignmentToFunctionParameterJS + gap = this.length; + } + //endregion + + //region Search for patterns + const result = this.stream.findFirstIn(patterns, this.start, this.length, this.backward); + // noinspection NonBlockStatementBodyJS, EqualityComparisonWithCoercionJS + if (result.id == -1) return result; + + if (this.backward) { + if (result.position < this.start - patterns[result.id].buffer.byteLength - gap) { + // noinspection ConditionalExpressionJS + return { + id: -1, + position: this.backward ? 0 : this.start + this.length + }; + } + } else { + if (result.position > this.start + patterns[result.id].buffer.byteLength + gap) { + // noinspection ConditionalExpressionJS + return { + id: -1, + position: this.backward ? 0 : this.start + this.length + }; + } + } + //endregion + + //region Create new values + this.start = result.position; + //endregion ; + + return result; + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols + /** + * Find all positions of any pattern from input array + * @param {Array.} patterns Array with patterns which should be found + * @returns {Array} + */ + findAllIn(patterns) { + // In case of "backward order" the start position is at the end on stream. + // In case of "normal order" the start position is at the begging of the stream. + // But in fact for search for all patterns we need to have start position in "normal order". + // noinspection ConditionalExpressionJS + const start = this.backward ? this.start - this.length : this.start; + + return this.stream.findAllIn(patterns, start, this.length); + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols, FunctionWithMultipleReturnPointsJS, OverlyComplexFunctionJS + /** + * Find first position of data, not included in patterns from input array + * @param {Array.} patterns Array with patterns which should be ommited + * @param {?number} gap Maximum gap between start position and position of nearest object + * @returns {*} + */ + findFirstNotIn(patterns, gap = null) { + //region Initial variables + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if (gap == null || gap > this._length) { + // noinspection AssignmentToFunctionParameterJS + gap = this._length; + } + //endregion + + //region Search for patterns + const result = this._stream.findFirstNotIn(patterns, this._start, this._length, this.backward); + // noinspection NonBlockStatementBodyJS, EqualityComparisonWithCoercionJS + if (result.left.id == -1 && result.right.id == -1) return result; + + if (this.backward) { + // noinspection EqualityComparisonWithCoercionJS + if (result.right.id != -1) { + if (result.right.position < this._start - patterns[result.right.id]._buffer.byteLength - gap) { + return { + left: { + id: -1, + position: this._start + }, + right: { + id: -1, + position: 0 + }, + value: new ByteStream() + }; + } + } + } else { + // noinspection EqualityComparisonWithCoercionJS + if (result.left.id != -1) { + if (result.left.position > this._start + patterns[result.left.id]._buffer.byteLength + gap) { + return { + left: { + id: -1, + position: this._start + }, + right: { + id: -1, + position: 0 + }, + value: new ByteStream() + }; + } + } + } + //endregion + + //region Create new values + if (this.backward) { + // noinspection NonBlockStatementBodyJS, EqualityComparisonWithCoercionJS + if (result.left.id == -1) this.start = 0;else this.start = result.left.position; + } else { + // noinspection NonBlockStatementBodyJS, EqualityComparisonWithCoercionJS + if (result.right.id == -1) this.start = this._start + this._length;else this.start = result.right.position; + } + //endregion ; + + return result; + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols + /** + * Find all positions of data, not included in patterns from input array + * @param {Array.} patterns Array with patterns which should be ommited + * @returns {Array} + */ + findAllNotIn(patterns) { + // In case of "backward order" the start position is at the end on stream. + // In case of "normal order" the start position is at the begging of the stream. + // But in fact for search for all patterns we need to have start position in "normal order". + // noinspection ConditionalExpressionJS + const start = this.backward ? this._start - this._length : this._start; + + return this._stream.findAllNotIn(patterns, start, this._length); + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols, FunctionWithMultipleReturnPointsJS + /** + * Find position of a sequence of any patterns from input array + * @param {Array.} patterns Array with patterns which should be ommited + * @param {?number} [length] Length to search sequence for + * @param {?number} [gap] Maximum gap between start position and position of nearest object + * @returns {*} + */ + findFirstSequence(patterns, length = null, gap = null) { + //region Initial variables + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if (length == null || length > this._length) { + // noinspection AssignmentToFunctionParameterJS + length = this._length; + } + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if (gap == null || gap > length) { + // noinspection AssignmentToFunctionParameterJS + gap = length; + } + //endregion + + //region Search for sequence + const result = this._stream.findFirstSequence(patterns, this._start, length, this.backward); + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, NonBlockStatementBodyJS, EqualityComparisonWithCoercionJS + if (result.value.buffer.byteLength == 0) return result; + + if (this.backward) { + if (result.position < this._start - result.value._buffer.byteLength - gap) { + return { + position: -1, + value: new ByteStream() + }; + } + } else { + if (result.position > this._start + result.value._buffer.byteLength + gap) { + return { + position: -1, + value: new ByteStream() + }; + } + } + //endregion + + //region Create new values + this.start = result.position; + //endregion ; + + return result; + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols + /** + * Find position of a sequence of any patterns from input array + * @param {Array.} patterns Array with patterns which should be found + * @returns {Array} + */ + findAllSequences(patterns) { + // In case of "backward order" the start position is at the end on stream. + // In case of "normal order" the start position is at the begging of the stream. + // But in fact for search for all patterns we need to have start position in "normal order". + // noinspection ConditionalExpressionJS + const start = this.backward ? this.start - this.length : this.start; + + return this.stream.findAllSequences(patterns, start, this.length); + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols, FunctionWithMultipleReturnPointsJS + /** + * Find all paired patterns in the stream + * @param {ByteStream} leftPattern Left pattern to search for + * @param {ByteStream} rightPattern Right pattern to search for + * @param {?number} [gap] Maximum gap between start position and position of nearest object + * @returns {Array} + */ + findPairedPatterns(leftPattern, rightPattern, gap = null) { + //region Initial variables + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if (gap == null || gap > this.length) { + // noinspection AssignmentToFunctionParameterJS + gap = this.length; + } + //endregion + + // In case of "backward order" the start position is at the end on stream. + // In case of "normal order" the start position is at the begging of the stream. + // But in fact for search for all patterns we need to have start position in "normal order". + // noinspection ConditionalExpressionJS + const start = this.backward ? this.start - this.length : this.start; + + //region Search for patterns + const result = this.stream.findPairedPatterns(leftPattern, rightPattern, start, this.length); + if (result.length) { + if (this.backward) { + // noinspection NonBlockStatementBodyJS + if (result[0].right < this.start - rightPattern.buffer.byteLength - gap) return []; + } else { + // noinspection NonBlockStatementBodyJS + if (result[0].left > this.start + leftPattern.buffer.byteLength + gap) return []; + } + } + //endregion + + return result; + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols, FunctionWithMultipleReturnPointsJS + /** + * Find all paired patterns in the stream + * @param {Array.} leftPatterns Array of left patterns to search for + * @param {Array.} rightPatterns Array of right patterns to search for + * @param {?number} [gap] Maximum gap between start position and position of nearest object + * @returns {Array} + */ + findPairedArrays(leftPatterns, rightPatterns, gap = null) { + //region Initial variables + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if (gap == null || gap > this.length) { + // noinspection AssignmentToFunctionParameterJS + gap = this.length; + } + //endregion + + // In case of "backward order" the start position is at the end on stream. + // In case of "normal order" the start position is at the begging of the stream. + // But in fact for search for all patterns we need to have start position in "normal order". + // noinspection ConditionalExpressionJS + const start = this.backward ? this.start - this.length : this.start; + + //region Search for patterns + const result = this.stream.findPairedArrays(leftPatterns, rightPatterns, start, this.length); + if (result.length) { + if (this.backward) { + // noinspection NonBlockStatementBodyJS + if (result[0].right.position < this.start - rightPatterns[result[0].right.id].buffer.byteLength - gap) return []; + } else { + // noinspection NonBlockStatementBodyJS + if (result[0].left.position > this.start + leftPatterns[result[0].left.id].buffer.byteLength + gap) return []; + } + } + //endregion + + return result; + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols + /** + * Replace one patter with other + * @param {ByteStream} searchPattern The pattern to search for + * @param {ByteStream} replacePattern The pattern to replace initial pattern + * @returns {*} + */ + replacePattern(searchPattern, replacePattern) { + // In case of "backward order" the start position is at the end on stream. + // In case of "normal order" the start position is at the begging of the stream. + // But in fact for search for all patterns we need to have start position in "normal order". + // noinspection ConditionalExpressionJS + const start = this.backward ? this.start - this.length : this.start; + + return this.stream.replacePattern(searchPattern, replacePattern, start, this.length); + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols + /** + * Skip of any pattern from input array + * @param {Array.} patterns Array with patterns which should be ommited + * @returns {*} + */ + skipPatterns(patterns) { + const result = this.stream.skipPatterns(patterns, this.start, this.length, this.backward); + + //region Create new values + this.start = result; + //endregion ; + + return result; + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols, FunctionWithMultipleReturnPointsJS + /** + * Skip of any pattern from input array + * @param {Array.} patterns Array with patterns which should be ommited + * @returns {number} + */ + skipNotPatterns(patterns) { + const result = this.stream.skipNotPatterns(patterns, this.start, this.length, this.backward); + // noinspection NonBlockStatementBodyJS, EqualityComparisonWithCoercionJS + if (result == -1) return -1; + + //region Create new values + this.start = result; + //endregion ; + + return result; + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols + /** + * Append a new "Stream" content to the current "Stream" + * @param {ByteStream} stream A new "stream" to append to current "stream" + */ + append(stream) { + if (this._start + stream._buffer.byteLength > this._stream._buffer.byteLength) { + if (stream._buffer.byteLength > this.appendBlock) { + // noinspection MagicNumberJS + this.appendBlock = stream._buffer.byteLength + 1000; + } + + this._stream.realloc(this._stream._buffer.byteLength + this.appendBlock); + } + + this._stream._view.set(stream._view, this._start); + + this._length += stream._buffer.byteLength * 2; + this.start = this._start + stream._buffer.byteLength; + this.prevLength -= stream._buffer.byteLength * 2; + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols + /** + * Append a "view" content to the current "Stream" + * @param {Uint8Array} view A new "view" to append to current "stream" + */ + appendView(view) { + if (this._start + view.length > this._stream._buffer.byteLength) { + if (view.length > this.appendBlock) { + // noinspection MagicNumberJS + this.appendBlock = view.length + 1000; + } + + this._stream.realloc(this._stream._buffer.byteLength + this.appendBlock); + } + + this._stream._view.set(view, this._start); + + this._length += view.length * 2; + this.start = this._start + view.length; + this.prevLength -= view.length * 2; + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols + /** + * Append a new char to the current "Stream" + * @param {number} char A new char to append to current "stream" + */ + appendChar(char) { + if (this._start + 1 > this._stream._buffer.byteLength) { + // noinspection ConstantOnLefSideOfComparisonJS + if (1 > this.appendBlock) { + // noinspection MagicNumberJS + this.appendBlock = 1000; + } + + this._stream.realloc(this._stream._buffer.byteLength + this.appendBlock); + } + + this._stream._view[this._start] = char; + + this._length += 2; + this.start = this._start + 1; + this.prevLength -= 2; + } + //********************************************************************************** + // noinspection FunctionNamingConventionJS + /** + * Append a new number to the current "Stream" + * @param {number} number A new unsigned 16-bit integer to append to current "stream" + */ + appendUint16(number) { + if (this._start + 2 > this._stream._buffer.byteLength) { + // noinspection ConstantOnLefSideOfComparisonJS + if (2 > this.appendBlock) { + // noinspection MagicNumberJS + this.appendBlock = 1000; + } + + this._stream.realloc(this._stream._buffer.byteLength + this.appendBlock); + } + + const value = new Uint16Array([number]); + const view = new Uint8Array(value.buffer); + + this._stream._view[this._start] = view[1]; + this._stream._view[this._start + 1] = view[0]; + + this._length += 4; + this.start = this._start + 2; + this.prevLength -= 4; + } + //********************************************************************************** + // noinspection FunctionNamingConventionJS + /** + * Append a new number to the current "Stream" + * @param {number} number A new unsigned 24-bit integer to append to current "stream" + */ + appendUint24(number) { + if (this._start + 3 > this._stream._buffer.byteLength) { + // noinspection ConstantOnLefSideOfComparisonJS + if (3 > this.appendBlock) { + // noinspection MagicNumberJS + this.appendBlock = 1000; + } + + this._stream.realloc(this._stream._buffer.byteLength + this.appendBlock); + } + + const value = new Uint32Array([number]); + const view = new Uint8Array(value.buffer); + + this._stream._view[this._start] = view[2]; + this._stream._view[this._start + 1] = view[1]; + this._stream._view[this._start + 2] = view[0]; + + this._length += 6; + this.start = this._start + 3; + this.prevLength -= 6; + } + //********************************************************************************** + // noinspection FunctionNamingConventionJS + /** + * Append a new number to the current "Stream" + * @param {number} number A new unsigned 32-bit integer to append to current "stream" + */ + appendUint32(number) { + if (this._start + 4 > this._stream._buffer.byteLength) { + // noinspection ConstantOnLefSideOfComparisonJS + if (4 > this.appendBlock) { + // noinspection MagicNumberJS + this.appendBlock = 1000; + } + + this._stream.realloc(this._stream._buffer.byteLength + this.appendBlock); + } + + const value = new Uint32Array([number]); + const view = new Uint8Array(value.buffer); + + this._stream._view[this._start] = view[3]; + this._stream._view[this._start + 1] = view[2]; + this._stream._view[this._start + 2] = view[1]; + this._stream._view[this._start + 3] = view[0]; + + this._length += 8; + this.start = this._start + 4; + this.prevLength -= 8; + } + //********************************************************************************** + // noinspection FunctionWithMultipleReturnPointsJS + /** + * Get a block of data + * @param {number} size Size of the data block to get + * @param {boolean} [changeLength=true] Should we change "length" and "start" value after reading the data block + * @returns {Array} + */ + getBlock(size, changeLength = true) { + //region Check input parameters + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, NonBlockStatementBodyJS + if (this._length <= 0) return []; + + if (this._length < size) { + // noinspection AssignmentToFunctionParameterJS + size = this._length; + } + //endregion + + //region Initial variables + let result; + //endregion + + //region Getting result depends on "backward" flag + if (this.backward) { + const buffer = this._stream._buffer.slice(this._length - size, this._length); + const view = new Uint8Array(buffer); + + result = new Array(size); + + // noinspection NonBlockStatementBodyJS + for (let i = 0; i < size; i++) result[size - 1 - i] = view[i]; + } else { + const buffer = this._stream._buffer.slice(this._start, this._start + size); + + // noinspection NestedFunctionCallJS + result = Array.from(new Uint8Array(buffer)); + } + //endregion + + //region Change "length" value if needed + if (changeLength) { + // noinspection ConditionalExpressionJS + this.start += this.backward ? -1 * size : size; + } + //endregion + + return result; + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols, FunctionWithMultipleReturnPointsJS, FunctionNamingConventionJS + /** + * Get 2-byte unsigned integer value + * @param {boolean} [changeLength=true] Should we change "length" and "start" value after reading the data block + * @returns {number} + */ + getUint16(changeLength = true) { + const block = this.getBlock(2, changeLength); + + //region Check posibility for convertion + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, NonBlockStatementBodyJS + if (block.length < 2) return 0; + //endregion + + //region Convert byte array to "Uint32Array" value + const value = new Uint16Array(1); + const view = new Uint8Array(value.buffer); + + view[0] = block[1]; + view[1] = block[0]; + //endregion + + return value[0]; + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols, FunctionWithMultipleReturnPointsJS, FunctionNamingConventionJS + /** + * Get 3-byte unsigned integer value + * @param {boolean} [changeLength=true] Should we change "length" and "start" value after reading the data block + * @returns {number} + */ + getUint24(changeLength = true) { + const block = this.getBlock(3, changeLength); + + //region Check posibility for convertion + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, NonBlockStatementBodyJS + if (block.length < 3) return 0; + //endregion + + //region Convert byte array to "Uint32Array" value + const value = new Uint32Array(1); + const view = new Uint8Array(value.buffer); + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, NonBlockStatementBodyJS + for (let i = 3; i >= 1; i--) view[3 - i] = block[i - 1]; + //endregion + + return value[0]; + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols, FunctionWithMultipleReturnPointsJS, FunctionNamingConventionJS + /** + * Get 4-byte unsigned integer value + * @param {boolean} [changeLength=true] Should we change "length" and "start" value after reading the data block + * @returns {number} + */ + getUint32(changeLength = true) { + const block = this.getBlock(4, changeLength); + + //region Check posibility for convertion + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, NonBlockStatementBodyJS + if (block.length < 4) return 0; + //endregion + + //region Convert byte array to "Uint32Array" value + const value = new Uint32Array(1); + const view = new Uint8Array(value.buffer); + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, NonBlockStatementBodyJS + for (let i = 3; i >= 0; i--) view[3 - i] = block[i]; + //endregion + + return value[0]; + } + //********************************************************************************** +} +exports.SeqStream = SeqStream; //************************************************************************************** +// noinspection FunctionWithMultipleLoopsJS, FunctionWithMultipleReturnPointsJS, OverlyComplexFunctionJS, FunctionTooLongJS +/** + * Get parsed values from "byte map" + * @param {ByteStream} stream Stream to parse data from + * @param {Object} map Object with information how to parse "byte map" + * @param {number} elements Number of elements in parsing byte map + * @param {?number} [start=null] Start position to parse from + * @param {?number} [length=null] Length of byte block to parse from + * @returns {*} + */ + +function parseByteMap(stream, map, elements, start = null, length = null) { + /* + Map example: + + let map = [ + { + type: "string", + name: "type", + minlength: 1, + maxlength: 1, + func: function(array) + { + let result = { + status: (-1), + length: 1 + }; + + switch(array[0]) + { + case 0x6E: // "n" + result.value = "n"; + break; + case 0x66: // "f" + result.value = "f"; + break; + default: + return result; + } + + result.status = 1; + + return result; + } + }, + { + type: "check", + minlength: 1, + maxlength: 2, + func: function(array) + { + let position = (-1); + + if(array[0] == 0x0A) + position = 1; + if(array[1] == 0x0A) + position = 2; + + return { + status: (position > 0) ? 1 : (-1), + length: position + }; + } + } + ]; + */ + + //region Initial variables + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if (start === null) { + // noinspection AssignmentToFunctionParameterJS + start = 0; + } + + // noinspection NonBlockStatementBodyJS + if (start > stream.buffer.byteLength - 1) return false; + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if (length === null) { + // noinspection AssignmentToFunctionParameterJS + length = stream.buffer.byteLength - start; + } + + if (length > stream.buffer.byteLength - start) { + // noinspection AssignmentToFunctionParameterJS + length = stream.buffer.byteLength - start; + } + + let dataView; + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, EqualityComparisonWithCoercionJS, NonBlockStatementBodyJS + if (start == 0 && length == stream.buffer.byteLength) dataView = stream.view;else dataView = new Uint8Array(stream.buffer, start, length); + + const resultArray = new Array(elements); + let elementsCount = 0; + + let count = 0; + const mapLength = map.length; + //endregion + + //region Parse all byte, structure by structure + while (count < length) { + let structureLength = 0; + + resultArray[elementsCount] = {}; + + for (let i = 0; i < mapLength; i++) { + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, JSUnresolvedVariable, EqualityComparisonWithCoercionJS + if (map[i].maxlength == 0) { + // noinspection NonBlockStatementBodyJS + if ("defaultValue" in map[i]) resultArray[elementsCount][map[i].name] = map[i].defaultValue; + + // noinspection ContinueStatementJS + continue; + } + + // noinspection JSUnresolvedVariable + const array = new Array(map[i].maxlength); + + // noinspection JSUnresolvedVariable + for (let j = 0; j < map[i].maxlength; j++) { + // noinspection IncrementDecrementResultUsedJS + array[j] = dataView[count++]; + } + + // noinspection JSUnresolvedVariable + const result = map[i].func(array); + // noinspection EqualityComparisonWithCoercionJS, NonBlockStatementBodyJS + if (result.status == -1) { + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, NonBlockStatementBodyJS, EqualityComparisonWithCoercionJS + if (resultArray.length == 1) return []; + + return resultArray.slice(0, resultArray.length - 1); + } + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, EqualityComparisonWithCoercionJS, NonBlockStatementBodyJS + if (map[i].type != "check") resultArray[elementsCount][map[i].name] = result.value; + + // noinspection JSUnresolvedVariable + count -= map[i].maxlength - result.length; + structureLength += result.length; + } + + // noinspection IncrementDecrementResultUsedJS + resultArray[elementsCount++].structureLength = structureLength; + } + //endregion + + return resultArray; +} +//************************************************************************************** +//region "Bits-to-string" array +const bitsToStringArray = ["00000000", "00000001", "00000010", "00000011", "00000100", "00000101", "00000110", "00000111", "00001000", "00001001", "00001010", "00001011", "00001100", "00001101", "00001110", "00001111", "00010000", "00010001", "00010010", "00010011", "00010100", "00010101", "00010110", "00010111", "00011000", "00011001", "00011010", "00011011", "00011100", "00011101", "00011110", "00011111", "00100000", "00100001", "00100010", "00100011", "00100100", "00100101", "00100110", "00100111", "00101000", "00101001", "00101010", "00101011", "00101100", "00101101", "00101110", "00101111", "00110000", "00110001", "00110010", "00110011", "00110100", "00110101", "00110110", "00110111", "00111000", "00111001", "00111010", "00111011", "00111100", "00111101", "00111110", "00111111", "01000000", "01000001", "01000010", "01000011", "01000100", "01000101", "01000110", "01000111", "01001000", "01001001", "01001010", "01001011", "01001100", "01001101", "01001110", "01001111", "01010000", "01010001", "01010010", "01010011", "01010100", "01010101", "01010110", "01010111", "01011000", "01011001", "01011010", "01011011", "01011100", "01011101", "01011110", "01011111", "01100000", "01100001", "01100010", "01100011", "01100100", "01100101", "01100110", "01100111", "01101000", "01101001", "01101010", "01101011", "01101100", "01101101", "01101110", "01101111", "01110000", "01110001", "01110010", "01110011", "01110100", "01110101", "01110110", "01110111", "01111000", "01111001", "01111010", "01111011", "01111100", "01111101", "01111110", "01111111", "10000000", "10000001", "10000010", "10000011", "10000100", "10000101", "10000110", "10000111", "10001000", "10001001", "10001010", "10001011", "10001100", "10001101", "10001110", "10001111", "10010000", "10010001", "10010010", "10010011", "10010100", "10010101", "10010110", "10010111", "10011000", "10011001", "10011010", "10011011", "10011100", "10011101", "10011110", "10011111", "10100000", "10100001", "10100010", "10100011", "10100100", "10100101", "10100110", "10100111", "10101000", "10101001", "10101010", "10101011", "10101100", "10101101", "10101110", "10101111", "10110000", "10110001", "10110010", "10110011", "10110100", "10110101", "10110110", "10110111", "10111000", "10111001", "10111010", "10111011", "10111100", "10111101", "10111110", "10111111", "11000000", "11000001", "11000010", "11000011", "11000100", "11000101", "11000110", "11000111", "11001000", "11001001", "11001010", "11001011", "11001100", "11001101", "11001110", "11001111", "11010000", "11010001", "11010010", "11010011", "11010100", "11010101", "11010110", "11010111", "11011000", "11011001", "11011010", "11011011", "11011100", "11011101", "11011110", "11011111", "11100000", "11100001", "11100010", "11100011", "11100100", "11100101", "11100110", "11100111", "11101000", "11101001", "11101010", "11101011", "11101100", "11101101", "11101110", "11101111", "11110000", "11110001", "11110010", "11110011", "11110100", "11110101", "11110110", "11110111", "11111000", "11111001", "11111010", "11111011", "11111100", "11111101", "11111110", "11111111"]; +//endregion +//************************************************************************************** +class BitStream { + //********************************************************************************** + /** + * Constructor for "BitStream" class + * @param {{[byteStream]: ByteStream, [view]: Uint8Array, [buffer]: ArrayBuffer, [string]: string, [bitsCount]: number}} parameters + */ + constructor(parameters = {}) { + this.buffer = new ArrayBuffer(0); + this.view = new Uint8Array(this.buffer); + + this.bitsCount = 0; // Number of bits stored in current "BitStream" + + var _iteratorNormalCompletion3 = true; + var _didIteratorError3 = false; + var _iteratorError3 = undefined; + + try { + for (var _iterator3 = Object.keys(parameters)[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) { + const key = _step3.value; + + switch (key) { + case "byteStream": + this.fromByteStream(parameters.byteStream); + break; + case "view": + this.fromUint8Array(parameters.view); + break; + case "buffer": + this.fromArrayBuffer(parameters.buffer); + break; + case "string": + this.fromString(parameters.string); + break; + case "uint32": + this.fromUint32(parameters.uint32); + break; + case "bitsCount": + this.bitsCount = parameters.bitsCount; + break; + default: + } + } + } catch (err) { + _didIteratorError3 = true; + _iteratorError3 = err; + } finally { + try { + if (!_iteratorNormalCompletion3 && _iterator3.return) { + _iterator3.return(); + } + } finally { + if (_didIteratorError3) { + throw _iteratorError3; + } + } + } + } + //********************************************************************************** + /** + * Clear existing stream + */ + clear() { + this.buffer = new ArrayBuffer(0); + this.view = new Uint8Array(this.buffer); + + this.bitsCount = 0; + } + //********************************************************************************** + /** + * Initialize "BitStream" by data from existing "ByteStream" + * @param {ByteStream} stream + */ + fromByteStream(stream) { + this.buffer = stream.buffer.slice(0); + this.view = new Uint8Array(this.buffer); + + this.bitsCount = this.view.length << 3; + } + //********************************************************************************** + /** + * Initialize "BitStream" object from existing "ArrayBuffer" + * @param {ArrayBuffer} array The ArrayBuffer to copy from + */ + fromArrayBuffer(array) { + this.buffer = array.slice(0); + this.view = new Uint8Array(this.buffer); + + this.bitsCount = this.view.length << 3; + } + //********************************************************************************** + // noinspection FunctionNamingConventionJS + /** + * Initialize "BitStream" object from existing "Uint8Array" + * @param {Uint8Array} array The Uint8Array to copy from + */ + fromUint8Array(array) { + this.buffer = new ArrayBuffer(array.length); + this.view = new Uint8Array(this.buffer); + + this.view.set(array); + + this.bitsCount = this.view.length << 3; + } + //********************************************************************************** + /** + * Initialize "BitStream" object from existing bit string + * @param {string} string The string to initialize from + */ + fromString(string) { + //region Initial variables + const stringLength = string.length; + + // noinspection ConditionalExpressionJS + this.buffer = new ArrayBuffer((stringLength >> 3) + (stringLength % 8 ? 1 : 0)); + this.view = new Uint8Array(this.buffer); + + this.bitsCount = (stringLength >> 3) + 1 << 3; // In order to handle correct shifting + + let byteIndex = 0; + //endregion + + //region Convert from "bit string" to bytes + for (let i = 0; i < stringLength; i++) { + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, EqualityComparisonWithCoercionJS, NonBlockStatementBodyJS + if (string[i] == "1") this.view[byteIndex] |= 1 << 7 - i % 8; + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, EqualityComparisonWithCoercionJS, NonBlockStatementBodyJS + if (i && (i + 1) % 8 == 0) byteIndex++; + } + //endregion + + //region Shift "BitStream" into correct position + // noinspection NonBlockStatementBodyJS + if (stringLength % 8) this.shiftRight(8 - stringLength % 8); + //endregion + + //region Change "bitsCount" + this.bitsCount = stringLength; + //endregion + } + //********************************************************************************** + /** + * Initialize "BitStream" object from existing uint32 number + * @param {Number} number The string to initialize from + */ + fromUint32(uint32) { + this.buffer = new ArrayBuffer(4); + this.view = new Uint8Array(this.buffer); + + const value = new Uint32Array([uint32]); + const view = new Uint8Array(value.buffer); + + for (let i = 3; i >= 0; i--) this.view[i] = view[3 - i]; + + this.bitsCount = 32; + } + //********************************************************************************** + /** + * Represent "BitStream" object content as a string + * @param {?number} [start=null] Start number to convert to string from + * @param {?number} [length=null] Length of BitStream to convert to string + * @returns {string} + */ + toString(start = null, length = null) { + //region Check input parameters + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if (start == null) { + // noinspection AssignmentToFunctionParameterJS + start = 0; + } + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if (start >= this.view.length || start < 0) { + // noinspection AssignmentToFunctionParameterJS + start = 0; + } + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if (length == null) { + // noinspection AssignmentToFunctionParameterJS + length = this.view.length - start; + } + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if (length >= this.view.length || length < 0) { + // noinspection AssignmentToFunctionParameterJS + length = this.view.length - start; + } + //endregion + + //region Initial variables + const result = []; + //endregion + + //region Convert from bytes to "bit string" + // noinspection NonBlockStatementBodyJS + for (let i = start; i < start + length; i++) result.push(bitsToStringArray[this.view[i]]); + //endregion + + // noinspection ChainedFunctionCallJS + return result.join("").slice((this.view.length << 3) - this.bitsCount); + } + //********************************************************************************** + // noinspection FunctionWithMultipleReturnPointsJS + /** + * Shift entire "BitStream" value right to number of bits + * @param {number} shift Number of bits to shift value + * @param {boolean} [needShrink=true] Need to shrink result or not + */ + shiftRight(shift, needShrink = true) { + //region Check parameters + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, EqualityComparisonWithCoercionJS, NonBlockStatementBodyJS + if (this.view.length == 0) return; + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, NonBlockStatementBodyJS + if (shift < 0 || shift > 8) throw new Error("The \"shift\" parameter must be in range 0-8"); + + // noinspection NonBlockStatementBodyJS + if (shift > this.bitsCount) throw new Error("The \"shift\" parameter can not be bigger than \"this.bitsCount\""); + //endregion + + //region Initial variables + // noinspection MagicNumberJS + const shiftMask = 0xFF >> 8 - shift; + this.view[this.view.length - 1] >>= shift; + //endregion + + //region Shift value + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + for (let i = this.view.length - 2; i >= 0; i--) { + // noinspection NonShortCircuitBooleanExpressionJS + this.view[i + 1] |= (this.view[i] & shiftMask) << 8 - shift; + this.view[i] >>= shift; + } + //endregion + + //region Decrease number of bits stored into value + this.bitsCount -= shift; + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, EqualityComparisonWithCoercionJS, NonBlockStatementBodyJS + if (this.bitsCount == 0) this.clear(); + //endregion + + //region Change stream size if needed + // noinspection NonBlockStatementBodyJS + if (needShrink) this.shrink(); + //endregion + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols, FunctionWithMultipleReturnPointsJS + /** + * Shift entire "BitStream" value left to number of bits + * @param {number} shift Number of bits to shift value + */ + shiftLeft(shift) { + /* + NOTE: We do not really shift value because of internal structure of "BitStream": + all bytes inside "BitStream" are aligned to right position. So, even if we will + really shift value to left after that we will need again shift it right to the + same number of bits. Thus all that we do here is hiding of left bits and descresing + the "bitsCount" number. + */ + + //region Check parameters + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, EqualityComparisonWithCoercionJS, NonBlockStatementBodyJS + if (this.view.length == 0) return; + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, NonBlockStatementBodyJS + if (shift < 0 || shift > 8) throw new Error("The \"shift\" parameter must be in range 0-8"); + + // noinspection NonBlockStatementBodyJS + if (shift > this.bitsCount) throw new Error("The \"shift\" parameter can not be bigger than \"this.bitsCount\""); + //endregion + + //region Remove shifted bits + // noinspection MagicNumberJS, NonShortCircuitBooleanExpressionJS + const bitsOffset = this.bitsCount & 0x07; + if (bitsOffset > shift) { + // noinspection MagicNumberJS + this.view[0] &= 0xFF >> bitsOffset + shift; + } else { + //region Change size of buffer + const buffer = new ArrayBuffer(this.buffer.byteLength - 1); + const view = new Uint8Array(buffer); + + // noinspection NestedFunctionCallJS + view.set(new Uint8Array(this.buffer, 1, this.buffer.byteLength - 1)); + //endregion + + //region Mask item with index 0 + // noinspection MagicNumberJS + view[0] &= 0xFF >> shift - bitsOffset; + //endregion + + //region Store final array into current stream + this.buffer = buffer.slice(0); + this.view = new Uint8Array(this.buffer); + //endregion + } + //endregion + + //region Decrease number of bits stored into value + this.bitsCount -= shift; + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, EqualityComparisonWithCoercionJS, NonBlockStatementBodyJS + if (this.bitsCount == 0) this.clear(); + //endregion + } + //********************************************************************************** + // noinspection FunctionWithMultipleReturnPointsJS, FunctionTooLongJS + /** + * Return slice of existing "BitStream" + * @param {?number} [start=null] Start position of the slice (in bits) + * @param {?number} [end=null] End position of the slice (in bits) + * @returns {BitStream} + */ + slice(start = null, end = null) { + //region Make ability to pass non-value bits + let valueShift = 0; + // noinspection NonBlockStatementBodyJS + if (this.bitsCount % 8) valueShift = 8 - this.bitsCount % 8; + + // noinspection AssignmentToFunctionParameterJS + start += valueShift; + // noinspection AssignmentToFunctionParameterJS + end += valueShift; + //endregion + + //region Initial variables + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if (start == null) { + // noinspection AssignmentToFunctionParameterJS + start = 0; + } + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, NonBlockStatementBodyJS + if (start < 0 || start > (this.view.length << 3) - 1) return new BitStream(); //("Wrong start position: " + start); + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if (end == null) { + // noinspection AssignmentToFunctionParameterJS + end = (this.view.length << 3) - 1; + } + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, NonBlockStatementBodyJS + if (end < 0 || end > (this.view.length << 3) - 1) return new BitStream(); //("Wrong end position: " + end); + + // noinspection NonBlockStatementBodyJS + if (end - start + 1 > this.bitsCount) return new BitStream(); //("Maximum length is " + this.bitsCount); + + const startIndex = start >> 3; + // noinspection MagicNumberJS, NonShortCircuitBooleanExpressionJS + const startOffset = start & 0x07; + + const endIndex = end >> 3; + // noinspection MagicNumberJS, NonShortCircuitBooleanExpressionJS + const endOffset = end & 0x07; + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, ConditionalExpressionJS, EqualityComparisonWithCoercionJS + const bitsLength = endIndex - startIndex == 0 ? 1 : endIndex - startIndex + 1; + + const result = new BitStream(); + //endregion + + //region Store "primary bytes" + result.buffer = new ArrayBuffer(bitsLength); + result.view = new Uint8Array(result.buffer); + result.bitsCount = bitsLength << 3; + + // noinspection NestedFunctionCallJS + result.view.set(new Uint8Array(this.buffer, startIndex, bitsLength)); + //endregion + + //region Change "start byte" + // noinspection MagicNumberJS + result.view[0] &= 0xFF >> startOffset; + //endregion + + //region Change "end byte" + // noinspection MagicNumberJS + result.view[bitsLength] &= 0xFF << 7 - endOffset; + //endregion + + //region Shift result array to right + // noinspection NonBlockStatementBodyJS + if (7 - endOffset) result.shiftRight(7 - endOffset, false); + //endregion + + //region Set final number of bits + result.bitsCount = end - start + 1; + //endregion + + //region Cut unnecessary bytes from result + result.shrink(); + //endregion + + return result; + } + //********************************************************************************** + // noinspection FunctionWithMultipleReturnPointsJS + /** + * Return copy of existing "BitStream" + * @param {?number} [start=null] Start position of the copy (in bits) + * @param {?number} [length=null] Length of the copy (in bits) + * @returns {BitStream} + */ + copy(start = null, length = null) { + //region Check input parameters + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, NonBlockStatementBodyJS + if (start < 0 || start > (this.view.length << 3) - 1) return new BitStream(); //("Wrong start position: " + start); + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if (length === null) { + // noinspection AssignmentToFunctionParameterJS + length = (this.view.length << 3) - start - 1; + } + + // noinspection NonBlockStatementBodyJS + if (length > this.bitsCount) return new BitStream(); //("Maximum length is " + this.bitsCount); + //endregion + + return this.slice(start, start + length - 1); + } + //********************************************************************************** + /** + * Shrink unnecessary bytes in current stream accordingly to "bitsCount" value + */ + shrink() { + // noinspection ConditionalExpressionJS + const currentLength = (this.bitsCount >> 3) + (this.bitsCount % 8 ? 1 : 0); + if (currentLength < this.buffer.byteLength) { + //region Change size of buffer + const buffer = new ArrayBuffer(currentLength); + const view = new Uint8Array(buffer); + + // noinspection NestedFunctionCallJS + view.set(new Uint8Array(this.buffer, this.buffer.byteLength - currentLength, currentLength)); + //endregion + + //region Store final array into current stream + this.buffer = buffer.slice(0); + this.view = new Uint8Array(this.buffer); + //endregion + } + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols + /** + * Reverse bits order in each byte in the stream + * Got it from here: http://graphics.stanford.edu/~seander/bithacks.html#ReverseByteWith32Bits + */ + reverseBytes() { + //region Reverse bits order in each byte in the stream + for (let i = 0; i < this.view.length; i++) { + // noinspection MagicNumberJS, NonShortCircuitBooleanExpressionJS + this.view[i] = (this.view[i] * 0x0802 & 0x22110 | this.view[i] * 0x8020 & 0x88440) * 0x10101 >> 16; + } + //endregion + + //region Shift "most significant" byte + if (this.bitsCount % 8) { + // noinspection ConditionalExpressionJS + const currentLength = (this.bitsCount >> 3) + (this.bitsCount % 8 ? 1 : 0); + // noinspection MagicNumberJS, NonShortCircuitBooleanExpressionJS + this.view[this.view.length - currentLength] >>= 8 - (this.bitsCount & 0x07); + } + //endregion + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols + /** + * Reverse all bits in entire "BitStream" + */ + reverseValue() { + const initialValue = this.toString(); + const initialValueLength = initialValue.length; + + const reversedValue = new Array(initialValueLength); + + // noinspection NonBlockStatementBodyJS + for (let i = 0; i < initialValueLength; i++) reversedValue[initialValueLength - 1 - i] = initialValue[i]; + + // noinspection NestedFunctionCallJS + this.fromString(reversedValue.join("")); + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols, FunctionWithMultipleReturnPointsJS + /** + * Trying to represent entire "BitStream" as an unsigned integer. + * @return {number} + */ + getNumberValue() { + //region Initial variables + const byteLength = this.buffer.byteLength - 1; + //endregion + + //region Check posibility for convertion + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, NonBlockStatementBodyJS + if (byteLength > 3) return -1; + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, EqualityComparisonWithCoercionJS, NonBlockStatementBodyJS + if (byteLength == -1) return 0; + //endregion + + //region Convert byte array to "Uint32Array" value + const value = new Uint32Array(1); + const view = new Uint8Array(value.buffer); + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, NonBlockStatementBodyJS + for (let i = byteLength; i >= 0; i--) view[byteLength - i] = this.view[i]; + //endregion + + return value[0]; + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols + /** + * Find any bit pattern in "BitStream" + * @param {BitStream} pattern Stream having pattern value + * @param {?number} [start=null] Start position to search from + * @param {?number} [length=null] Length of byte block to search at + * @param {boolean} [backward=false] Flag to search in backward order + * @returns {number} + */ + findPattern(pattern, start = null, length = null, backward = false) { + //region Convert "BitStream" values to "ByteStream" + const stringStream = new ByteStream({ + string: this.toString() + }); + const stringPattern = new ByteStream({ + string: pattern.toString() + }); + //endregion + + return stringStream.findPattern(stringPattern, start, length, backward); + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols + /** + * Find first position of any pattern from input array + * @param {Array.} patterns Array with patterns which should be found + * @param {?number} [start=null] Start position to search from + * @param {?number} [length=null] Length of byte block to search at + * @param {boolean} [backward=false] Flag to search in backward order + * @returns {{id: number, position: number}} + */ + findFirstIn(patterns, start = null, length = null, backward = false) { + //region Convert "BitStream" values to "ByteStream" + const stringStream = new ByteStream({ + string: this.toString() + }); + + const stringPatterns = new Array(patterns.length); + + for (let i = 0; i < patterns.length; i++) { + stringPatterns[i] = new ByteStream({ + string: patterns[i].toString() + }); + } + //endregion + + return stringStream.findFirstIn(stringPatterns, start, length, backward); + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols + /** + * Find all positions of any pattern from input array + * @param {Array.} patterns Array with patterns which should be found + * @param {?number} [start=null] Start position to search from + * @param {?number} [length=null] Length of byte block to search at + * @returns {Array} + */ + findAllIn(patterns, start = null, length = null) { + //region Convert "BitStream" values to "ByteStream" + const stringStream = new ByteStream({ + string: this.toString() + }); + + const stringPatterns = new Array(patterns.length); + + for (let i = 0; i < patterns.length; i++) { + stringPatterns[i] = new ByteStream({ + string: patterns[i].toString() + }); + } + //endregion + + return stringStream.findAllIn(stringPatterns, start, length); + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols + /** + * Find all positions of a pattern + * @param {BitStream} pattern Stream having pattern value + * @param {?number} [start=null] Start position to search from + * @param {?number} [length=null] Length of byte block to search at + * @returns {Array|number} + */ + findAllPatternIn(pattern, start = null, length = null) { + //region Convert "BitStream" values to "ByteStream" + const stringStream = new ByteStream({ + string: this.toString() + }); + const stringPattern = new ByteStream({ + string: pattern.toString() + }); + //endregion + + return stringStream.findAllPatternIn(stringPattern, start, length); + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols + /** + * Find first position of data, not included in patterns from input array + * @param {Array.} patterns Array with patterns which should be found + * @param {?number} [start=null] Start position to search from + * @param {?number} [length=null] Length of byte block to search at + * @param {boolean} [backward=false] Flag to search in backward order + * @returns {{left: {id: number, position: *}, right: {id: number, position: number}, value: ByteStream}} + */ + findFirstNotIn(patterns, start = null, length = null, backward = false) { + //region Convert "BitStream" values to "ByteStream" + const stringStream = new ByteStream({ + string: this.toString() + }); + + const stringPatterns = new Array(patterns.length); + + for (let i = 0; i < patterns.length; i++) { + stringPatterns[i] = new ByteStream({ + string: patterns[i].toString() + }); + } + //endregion + + return stringStream.findFirstNotIn(stringPatterns, start, length, backward); + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols + /** + * Find all positions of data, not included in patterns from input array + * @param {Array.} patterns Array with patterns which should be found + * @param {?number} [start=null] Start position to search from + * @param {?number} [length=null] Length of byte block to search at + * @returns {Array} + */ + findAllNotIn(patterns, start = null, length = null) { + //region Convert "BitStream" values to "ByteStream" + const stringStream = new ByteStream({ + string: this.toString() + }); + + const stringPatterns = new Array(patterns.length); + + for (let i = 0; i < patterns.length; i++) { + stringPatterns[i] = new ByteStream({ + string: patterns[i].toString() + }); + } + //endregion + + return stringStream.findAllNotIn(stringPatterns, start, length); + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols + /** + * Find position of a sequence of any patterns from input array + * @param {Array.} patterns Array with patterns which should be found + * @param {?number} [start=null] Start position to search from + * @param {?number} [length=null] Length of byte block to search at + * @param {boolean} [backward=false] Flag to search in backward order + * @returns {{position, value}|*} + */ + findFirstSequence(patterns, start = null, length = null, backward = false) { + //region Convert "BitStream" values to "ByteStream" + const stringStream = new ByteStream({ + string: this.toString() + }); + + const stringPatterns = new Array(patterns.length); + + for (let i = 0; i < patterns.length; i++) { + stringPatterns[i] = new ByteStream({ + string: patterns[i].toString() + }); + } + //endregion + + return stringStream.findFirstSequence(stringPatterns, start, length, backward); + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols + /** + * Find position of a sequence of any patterns from input array + * @param {Array.} patterns Array with patterns which should be found + * @param {?number} [start=null] Start position to search from + * @param {?number} [length=null] Length of byte block to search at + * @returns {Array} + */ + findAllSequences(patterns, start, length) { + //region Convert "BitStream" values to "ByteStream" + const stringStream = new ByteStream({ + string: this.toString() + }); + + const stringPatterns = new Array(patterns.length); + + for (let i = 0; i < patterns.length; i++) { + stringPatterns[i] = new ByteStream({ + string: patterns[i].toString() + }); + } + //endregion + + return stringStream.findAllSequences(stringPatterns, start, length); + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols + /** + * Find all paired patterns in the stream + * @param {BitStream} leftPattern Left pattern to search for + * @param {BitStream} rightPattern Right pattern to search for + * @param {?number} [start=null] Start position to search from + * @param {?number} [length=null] Length of byte block to search at + * @returns {Array} + */ + findPairedPatterns(leftPattern, rightPattern, start = null, length = null) { + //region Convert "BitStream" values to "ByteStream" + const stringStream = new ByteStream({ + string: this.toString() + }); + const stringLeftPattern = new ByteStream({ + string: leftPattern.toString() + }); + const stringRightPattern = new ByteStream({ + string: rightPattern.toString() + }); + //endregion + + return stringStream.findPairedPatterns(stringLeftPattern, stringRightPattern, start, length); + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols, FunctionWithMultipleLoopsJS + /** + * Find all paired patterns in the stream + * @param {Array.} inputLeftPatterns Array of left patterns to search for + * @param {Array.} inputRightPatterns Array of right patterns to search for + * @param {?number} [start=null] Start position to search from + * @param {?number} [length=null] Length of byte block to search at + * @returns {Array} + */ + findPairedArrays(inputLeftPatterns, inputRightPatterns, start = null, length = null) { + //region Convert "BitStream" values to "ByteStream" + const stringStream = new ByteStream({ + string: this.toString() + }); + + const stringLeftPatterns = new Array(inputLeftPatterns.length); + + for (let i = 0; i < inputLeftPatterns.length; i++) { + stringLeftPatterns[i] = new ByteStream({ + string: inputLeftPatterns[i].toString() + }); + } + + const stringRightPatterns = new Array(inputRightPatterns.length); + + for (let i = 0; i < inputRightPatterns.length; i++) { + stringRightPatterns[i] = new ByteStream({ + string: inputRightPatterns[i].toString() + }); + } + //endregion + + return stringStream.findPairedArrays(stringLeftPatterns, stringRightPatterns, start, length); + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols, FunctionWithMultipleReturnPointsJS + /** + * Replace one pattern with other + * @param {BitStream} searchPattern The pattern to search for + * @param {BitStream} replacePattern The pattern to replace initial pattern + * @param {?number} [start=null] Start position to search from + * @param {?number} [length=null] Length of byte block to search at + * @returns {boolean} + */ + replacePattern(searchPattern, replacePattern, start = null, length = null) { + //region Convert "BitStream" values to "ByteStream" + const stringStream = new ByteStream({ + string: this.toString() + }); + const stringSearchPattern = new ByteStream({ + string: searchPattern.toString() + }); + const stringReplacePattern = new ByteStream({ + string: replacePattern.toString() + }); + //endregion + + //region Re-initialize existing data + if (stringStream.findPairedPatterns(stringSearchPattern, stringReplacePattern, start, length)) { + // noinspection NestedFunctionCallJS + this.fromString(stringStream.toString()); + return true; + } + //endregion + + return false; + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols + /** + * Skip any pattern from input array + * @param {Array.} patterns Array with patterns which should be ommited + * @param {?number} [start=null] Start position to search from + * @param {?number} [length=null] Length of byte block to search at + * @param {boolean} [backward=false] Flag to search in backward order + * @returns {*} + */ + skipPatterns(patterns, start, length, backward) { + //region Convert "BitStream" values to "ByteStream" + const stringStream = new ByteStream({ + string: this.toString() + }); + + const stringPatterns = new Array(patterns.length); + + for (let i = 0; i < patterns.length; i++) { + stringPatterns[i] = new ByteStream({ + string: patterns[i].toString() + }); + } + //endregion + + return stringStream.skipPatterns(stringPatterns, start, length, backward); + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols + /** + * Skip any pattern not from input array + * @param {Array.} patterns Array with patterns which should be ommited + * @param {?number} [start=null] Start position to search from + * @param {?number} [length=null] Length of byte block to search at + * @param {boolean} [backward=false] Flag to search in backward order + * @returns {number} + */ + skipNotPatterns(patterns, start, length, backward) { + //region Convert "BitStream" values to "ByteStream" + const stringStream = new ByteStream({ + string: this.toString() + }); + + const stringPatterns = new Array(patterns.length); + + for (let i = 0; i < patterns.length; i++) { + stringPatterns[i] = new ByteStream({ + string: patterns[i].toString() + }); + } + //endregion + + return stringStream.skipNotPatterns(stringPatterns, start, length, backward); + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols + /** + * Append a new "BitStream" content to the current "BitStream" + * @param {BitStream} stream A new "stream" to append to current "stream" + */ + append(stream) { + //region Initialize current stream with new data + // noinspection NestedFunctionCallJS + this.fromString([this.toString(), stream.toString()].join("")); + //endregion + } + //********************************************************************************** +} +exports.BitStream = BitStream; //************************************************************************************** + +class SeqBitStream { + //********************************************************************************** + constructor(parameters = {}) { + //region Internal variables + this.stream = new BitStream(); + + this._start = 0; + this._length = this.stream.bitsCount; + + this.backward = false; + + this.appendBlock = 0; + //endregion + + var _iteratorNormalCompletion4 = true; + var _didIteratorError4 = false; + var _iteratorError4 = undefined; + + try { + for (var _iterator4 = Object.keys(parameters)[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) { + const key = _step4.value; + + switch (key) { + case "stream": + case "start": + case "length": + case "backward": + case "appendBlock": + this[key] = parameters[key]; + break; + default: + } + } + } catch (err) { + _didIteratorError4 = true; + _iteratorError4 = err; + } finally { + try { + if (!_iteratorNormalCompletion4 && _iterator4.return) { + _iterator4.return(); + } + } finally { + if (_didIteratorError4) { + throw _iteratorError4; + } + } + } + } + //********************************************************************************** + // noinspection FunctionWithMultipleReturnPointsJS + set start(value) { + // noinspection NonBlockStatementBodyJS + if (value > this.stream.bitsCount) return; + + // noinspection ConditionalExpressionJS + this._length -= this.backward ? this._start - value : value - this._start; + this._start = value; + + //region Initialization of "prev" internal variables + // noinspection JSUnusedGlobalSymbols + this.prevStart = this._start; + // noinspection JSUnusedGlobalSymbols + this.prevLength = this._length; + //endregion + } + //********************************************************************************** + get start() { + return this._start; + } + //********************************************************************************** + // noinspection FunctionWithMultipleReturnPointsJS + set length(value) { + // noinspection NonBlockStatementBodyJS + if (value > this.stream.bitsCount) return; + + // noinspection JSUnusedGlobalSymbols + this.prevLength = this._length; + this._length = value; + } + //********************************************************************************** + get length() { + return this._length; + } + //********************************************************************************** + set stream(value) { + this._stream = value; + + // noinspection JSUnusedGlobalSymbols + this.prevLength = this._length; + this._length = value.bitsCount; + + // noinspection JSUnusedGlobalSymbols + this.prevStart = this._start; + // noinspection ConditionalExpressionJS + this._start = this.backward ? this.length : 0; + } + //********************************************************************************** + get stream() { + return this._stream; + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols + /** + * Get next "length" bits from the stream + * @param {number} length Number of bits to read + * @returns {*} + */ + getBits(length) { + //region Check input parameters + if (this.start + length > this.stream.bitsCount) { + // noinspection AssignmentToFunctionParameterJS + length = this.stream.bitsCount - this.start; + } + //endregion + + //region Initial variables + let result; + //endregion + + //region Copy necessary length of bits + if (this.backward) { + result = this.stream.copy(this.start - length, length); + this.start -= result.bitsCount; + } else { + result = this.stream.copy(this.start, length); + this.start += result.bitsCount; + } + //endregion + + return result; + } + //********************************************************************************** + // noinspection FunctionTooLongJS + /** + * Get string representation for the next "length" bits from the stream + * @param {number} length Number of bits to read + * @returns {string} + */ + getBitsString(length) { + //region Check input parameters + if (this.start + length > this.stream.bitsCount) { + // noinspection AssignmentToFunctionParameterJS + length = this.stream.bitsCount - this.start; + } + //endregion + + //region Initial variables + let result = []; + + let start; + + // noinspection NonBlockStatementBodyJS + if (this.backward) start = this.start - length;else start = this.start; + + let end = this.start + length - 1; + + //region Make ability to pass non-value bits + let valueShift = 0; + // noinspection NonBlockStatementBodyJS + if (this.stream.bitsCount % 8) valueShift = 8 - this.stream.bitsCount % 8; + + start += valueShift; + end += valueShift; + //endregion + + const startIndex = start >> 3; + // noinspection MagicNumberJS, NonShortCircuitBooleanExpressionJS + const startOffset = start & 0x07; + + const endIndex = end >> 3; + // noinspection MagicNumberJS, NonShortCircuitBooleanExpressionJS + const endOffset = end & 0x07; + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, ConditionalExpressionJS, EqualityComparisonWithCoercionJS + const bitsLengthIndex = startIndex + (endIndex - startIndex == 0 ? 1 : endIndex - startIndex + 1); + //endregion + + //region Get string representation of bits + for (let i = startIndex; i < bitsLengthIndex; i++) { + let value = bitsToStringArray[this.stream.view[i]]; + + // noinspection EqualityComparisonWithCoercionJS, NonBlockStatementBodyJS + if (i == startIndex) value = value.slice(startOffset); + + // noinspection EqualityComparisonWithCoercionJS, NonBlockStatementBodyJS + if (i == bitsLengthIndex - 1) value = value.slice(0, endOffset - 7 + value.length); + + result.push(value); + } + + result = result.join(""); + //endregion + + //region Change internal values + // noinspection NonBlockStatementBodyJS + if (this.backward) this.start -= result.length;else this.start += result.length; + //endregion + + return result; + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols, FunctionWithMultipleLoopsJS, FunctionWithMultipleReturnPointsJS + /** + * Get number value representation of the next "length" bits from the stream, preliminary reversed + * @param {number} length Number of bits to read + * @returns {*} + */ + getBitsReversedValue(length) { + //region Initial variables + const initialValue = this.getBitsString(length); + const initialValueLength = initialValue.length; + + let byteIndex; + + const initialOffset = 8 - initialValueLength % 8; + + const reversedValue = new Array(initialValueLength); + + const value = new Uint32Array(1); + const valueView = new Uint8Array(value.buffer, 0, 4); + + let i; + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, MagicNumberJS, NonBlockStatementBodyJS + if (initialValueLength > 32) return -1; + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, MagicNumberJS, EqualityComparisonWithCoercionJS, NonBlockStatementBodyJS + if (length == 32) byteIndex = 3;else byteIndex = initialValueLength - 1 >> 3; + //endregion + + //region Reverse value + // noinspection NonBlockStatementBodyJS + for (i = 0; i < initialValueLength; i++) reversedValue[initialValueLength - 1 - i] = initialValue[i]; + //endregion + + //region Convert byte array to "Uint32Array" value + for (i = initialOffset; i < initialOffset + initialValueLength; i++) { + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, EqualityComparisonWithCoercionJS + if (reversedValue[i - initialOffset] == "1") { + // noinspection MagicNumberJS + valueView[byteIndex] |= 0x01 << 7 - i % 8; + } + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, EqualityComparisonWithCoercionJS, NonBlockStatementBodyJS + if (i && (i + 1) % 8 == 0) byteIndex--; + } + //endregion + + return value[0]; + } + //********************************************************************************** + /** + * Represent remaining bits in "BitStream" as a string + * @return {string} + */ + toString() { + const streamToDisplay = this.stream.copy(this.start, this.length); + return streamToDisplay.toString(); + } + //********************************************************************************** +} +exports.SeqBitStream = SeqBitStream; //************************************************************************************** + +},{}],2:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _GeneralName = _interopRequireDefault(require("./GeneralName.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC5280 + */ +class AccessDescription { + //********************************************************************************** + + /** + * Constructor for AccessDescription class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {string} + * @desc The type and format of the information are specified by the accessMethod field. This profile defines two accessMethod OIDs: id-ad-caIssuers and id-ad-ocsp + */ + this.accessMethod = (0, _pvutils.getParametersValue)(parameters, "accessMethod", AccessDescription.defaultValues("accessMethod")); + /** + * @type {GeneralName} + * @desc The accessLocation field specifies the location of the information + */ + + this.accessLocation = (0, _pvutils.getParametersValue)(parameters, "accessLocation", AccessDescription.defaultValues("accessLocation")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "accessMethod": + return ""; + + case "accessLocation": + return new _GeneralName.default(); + + default: + throw new Error(`Invalid member name for AccessDescription class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * AccessDescription ::= SEQUENCE { + * accessMethod OBJECT IDENTIFIER, + * accessLocation GeneralName } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [accessMethod] + * @property {string} [accessLocation] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [new asn1js.ObjectIdentifier({ + name: names.accessMethod || "" + }), _GeneralName.default.schema(names.accessLocation || {})] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["accessMethod", "accessLocation"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, AccessDescription.schema({ + names: { + accessMethod: "accessMethod", + accessLocation: { + names: { + blockName: "accessLocation" + } + } + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for AccessDescription"); //endregion + //region Get internal properties from parsed schema + + this.accessMethod = asn1.result.accessMethod.valueBlock.toString(); + this.accessLocation = new _GeneralName.default({ + schema: asn1.result.accessLocation + }); //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Construct and return new ASN.1 schema for this object + return new asn1js.Sequence({ + value: [new asn1js.ObjectIdentifier({ + value: this.accessMethod + }), this.accessLocation.toSchema()] + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + return { + accessMethod: this.accessMethod, + accessLocation: this.accessLocation.toJSON() + }; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = AccessDescription; + +},{"./GeneralName.js":40,"asn1js":112,"pvutils":113}],3:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC3161. Accuracy represents the time deviation around the UTC time contained in GeneralizedTime. + */ +class Accuracy { + //********************************************************************************** + + /** + * Constructor for Accuracy class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + if ("seconds" in parameters) + /** + * @type {number} + * @desc seconds + */ + this.seconds = (0, _pvutils.getParametersValue)(parameters, "seconds", Accuracy.defaultValues("seconds")); + if ("millis" in parameters) + /** + * @type {number} + * @desc millis + */ + this.millis = (0, _pvutils.getParametersValue)(parameters, "millis", Accuracy.defaultValues("millis")); + if ("micros" in parameters) + /** + * @type {number} + * @desc micros + */ + this.micros = (0, _pvutils.getParametersValue)(parameters, "micros", Accuracy.defaultValues("micros")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "seconds": + case "millis": + case "micros": + return 0; + + default: + throw new Error(`Invalid member name for Accuracy class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + + + static compareWithDefault(memberName, memberValue) { + switch (memberName) { + case "seconds": + case "millis": + case "micros": + return memberValue === Accuracy.defaultValues(memberName); + + default: + throw new Error(`Invalid member name for Accuracy class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * Accuracy ::= SEQUENCE { + * seconds INTEGER OPTIONAL, + * millis [0] INTEGER (1..999) OPTIONAL, + * micros [1] INTEGER (1..999) OPTIONAL } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [seconds] + * @property {string} [millis] + * @property {string} [micros] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + optional: true, + value: [new asn1js.Integer({ + optional: true, + name: names.seconds || "" + }), new asn1js.Primitive({ + name: names.millis || "", + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + } + }), new asn1js.Primitive({ + name: names.micros || "", + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + + } + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["seconds", "millis", "micros"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, Accuracy.schema({ + names: { + seconds: "seconds", + millis: "millis", + micros: "micros" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for Accuracy"); //endregion + //region Get internal properties from parsed schema + + if ("seconds" in asn1.result) this.seconds = asn1.result.seconds.valueBlock.valueDec; + + if ("millis" in asn1.result) { + const intMillis = new asn1js.Integer({ + valueHex: asn1.result.millis.valueBlock.valueHex + }); + this.millis = intMillis.valueBlock.valueDec; + } + + if ("micros" in asn1.result) { + const intMicros = new asn1js.Integer({ + valueHex: asn1.result.micros.valueBlock.valueHex + }); + this.micros = intMicros.valueBlock.valueDec; + } //endregion + + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Create array of output sequence + const outputArray = []; + if ("seconds" in this) outputArray.push(new asn1js.Integer({ + value: this.seconds + })); + + if ("millis" in this) { + const intMillis = new asn1js.Integer({ + value: this.millis + }); + outputArray.push(new asn1js.Primitive({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + valueHex: intMillis.valueBlock.valueHex + })); + } + + if ("micros" in this) { + const intMicros = new asn1js.Integer({ + value: this.micros + }); + outputArray.push(new asn1js.Primitive({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + + }, + valueHex: intMicros.valueBlock.valueHex + })); + } //endregion + //region Construct and return new ASN.1 schema for this object + + + return new asn1js.Sequence({ + value: outputArray + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + const _object = {}; + if ("seconds" in this) _object.seconds = this.seconds; + if ("millis" in this) _object.millis = this.millis; + if ("micros" in this) _object.micros = this.micros; + return _object; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = Accuracy; + +},{"asn1js":112,"pvutils":113}],4:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC5280 + */ +class AlgorithmIdentifier { + //********************************************************************************** + + /** + * Constructor for AlgorithmIdentifier class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + * @property {string} [algorithmId] ObjectIdentifier for algorithm (string representation) + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {string} + * @desc ObjectIdentifier for algorithm (string representation) + */ + this.algorithmId = (0, _pvutils.getParametersValue)(parameters, "algorithmId", AlgorithmIdentifier.defaultValues("algorithmId")); + if ("algorithmParams" in parameters) + /** + * @type {Object} + * @desc Any algorithm parameters + */ + this.algorithmParams = (0, _pvutils.getParametersValue)(parameters, "algorithmParams", AlgorithmIdentifier.defaultValues("algorithmParams")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "algorithmId": + return ""; + + case "algorithmParams": + return new asn1js.Any(); + + default: + throw new Error(`Invalid member name for AlgorithmIdentifier class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + + + static compareWithDefault(memberName, memberValue) { + switch (memberName) { + case "algorithmId": + return memberValue === ""; + + case "algorithmParams": + return memberValue instanceof asn1js.Any; + + default: + throw new Error(`Invalid member name for AlgorithmIdentifier class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * AlgorithmIdentifier ::= Sequence { + * algorithm OBJECT IDENTIFIER, + * parameters ANY DEFINED BY algorithm OPTIONAL } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} algorithmIdentifier ObjectIdentifier for the algorithm + * @property {string} algorithmParams Any algorithm parameters + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + optional: names.optional || false, + value: [new asn1js.ObjectIdentifier({ + name: names.algorithmIdentifier || "" + }), new asn1js.Any({ + name: names.algorithmParams || "", + optional: true + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["algorithm", "params"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, AlgorithmIdentifier.schema({ + names: { + algorithmIdentifier: "algorithm", + algorithmParams: "params" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for AlgorithmIdentifier"); //endregion + //region Get internal properties from parsed schema + + this.algorithmId = asn1.result.algorithm.valueBlock.toString(); + if ("params" in asn1.result) this.algorithmParams = asn1.result.params; //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Create array for output sequence + const outputArray = []; + outputArray.push(new asn1js.ObjectIdentifier({ + value: this.algorithmId + })); + if ("algorithmParams" in this && this.algorithmParams instanceof asn1js.Any === false) outputArray.push(this.algorithmParams); //endregion + //region Construct and return new ASN.1 schema for this object + + return new asn1js.Sequence({ + value: outputArray + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + const object = { + algorithmId: this.algorithmId + }; + if ("algorithmParams" in this && this.algorithmParams instanceof asn1js.Any === false) object.algorithmParams = this.algorithmParams.toJSON(); + return object; + } //********************************************************************************** + + /** + * Check that two "AlgorithmIdentifiers" are equal + * @param {AlgorithmIdentifier} algorithmIdentifier + * @returns {boolean} + */ + + + isEqual(algorithmIdentifier) { + //region Check input type + if (algorithmIdentifier instanceof AlgorithmIdentifier === false) return false; //endregion + //region Check "algorithm_id" + + if (this.algorithmId !== algorithmIdentifier.algorithmId) return false; //endregion + //region Check "algorithm_params" + + if ("algorithmParams" in this) { + if ("algorithmParams" in algorithmIdentifier) return JSON.stringify(this.algorithmParams) === JSON.stringify(algorithmIdentifier.algorithmParams); + return false; + } + + if ("algorithmParams" in algorithmIdentifier) return false; //endregion + + return true; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = AlgorithmIdentifier; + +},{"asn1js":112,"pvutils":113}],5:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _GeneralName = _interopRequireDefault(require("./GeneralName.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC5280 + */ +class AltName { + //********************************************************************************** + + /** + * Constructor for AltName class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {Array.} + * @desc Array of alternative names in GeneralName type + */ + this.altNames = (0, _pvutils.getParametersValue)(parameters, "altNames", AltName.defaultValues("altNames")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "altNames": + return []; + + default: + throw new Error(`Invalid member name for AltName class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * AltName ::= GeneralNames + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [altNames] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [new asn1js.Repeated({ + name: names.altNames || "", + value: _GeneralName.default.schema() + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["altNames"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, AltName.schema({ + names: { + altNames: "altNames" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for AltName"); //endregion + //region Get internal properties from parsed schema + + if ("altNames" in asn1.result) this.altNames = Array.from(asn1.result.altNames, element => new _GeneralName.default({ + schema: element + })); //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Construct and return new ASN.1 schema for this object + return new asn1js.Sequence({ + value: Array.from(this.altNames, element => element.toSchema()) + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + return { + altNames: Array.from(this.altNames, element => element.toJSON()) + }; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = AltName; + +},{"./GeneralName.js":40,"asn1js":112,"pvutils":113}],6:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC2986 + */ +class Attribute { + //********************************************************************************** + + /** + * Constructor for Attribute class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {string} + * @desc ObjectIdentifier for attribute (string representation) + */ + this.type = (0, _pvutils.getParametersValue)(parameters, "type", Attribute.defaultValues("type")); + /** + * @type {Array} + * @desc Any attribute values + */ + + this.values = (0, _pvutils.getParametersValue)(parameters, "values", Attribute.defaultValues("values")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "type": + return ""; + + case "values": + return []; + + default: + throw new Error(`Invalid member name for Attribute class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + + + static compareWithDefault(memberName, memberValue) { + switch (memberName) { + case "type": + return memberValue === ""; + + case "values": + return memberValue.length === 0; + + default: + throw new Error(`Invalid member name for Attribute class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * Attribute { ATTRIBUTE:IOSet } ::= SEQUENCE { + * type ATTRIBUTE.&id({IOSet}), + * values SET SIZE(1..MAX) OF ATTRIBUTE.&Type({IOSet}{@type}) + * } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [type] + * @property {string} [setName] + * @property {string} [values] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [new asn1js.ObjectIdentifier({ + name: names.type || "" + }), new asn1js.Set({ + name: names.setName || "", + value: [new asn1js.Repeated({ + name: names.values || "", + value: new asn1js.Any() + })] + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["type", "values"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, Attribute.schema({ + names: { + type: "type", + values: "values" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for Attribute"); //endregion + //region Get internal properties from parsed schema + + this.type = asn1.result.type.valueBlock.toString(); + this.values = asn1.result.values; //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Construct and return new ASN.1 schema for this object + return new asn1js.Sequence({ + value: [new asn1js.ObjectIdentifier({ + value: this.type + }), new asn1js.Set({ + value: this.values + })] + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + return { + type: this.type, + values: Array.from(this.values, element => element.toJSON()) + }; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = Attribute; + +},{"asn1js":112,"pvutils":113}],7:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = exports.AttributeCertificateInfoV1 = exports.IssuerSerial = exports.AttCertValidityPeriod = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _GeneralNames = _interopRequireDefault(require("./GeneralNames.js")); + +var _AlgorithmIdentifier = _interopRequireDefault(require("./AlgorithmIdentifier.js")); + +var _Attribute = _interopRequireDefault(require("./Attribute.js")); + +var _Extensions = _interopRequireDefault(require("./Extensions.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC5755 + */ +class AttCertValidityPeriod { + //********************************************************************************** + + /** + * Constructor for AttCertValidityPeriod class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {GeneralizedTime} + * @desc notBeforeTime + */ + this.notBeforeTime = (0, _pvutils.getParametersValue)(parameters, "notBeforeTime", AttCertValidityPeriod.defaultValues("notBeforeTime")); + /** + * @type {GeneralizedTime} + * @desc notAfterTime + */ + + this.notAfterTime = (0, _pvutils.getParametersValue)(parameters, "notAfterTime", AttCertValidityPeriod.defaultValues("notAfterTime")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "notBeforeTime": + case "notAfterTime": + return new Date(0, 0, 0); + + default: + throw new Error(`Invalid member name for AttCertValidityPeriod class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * AttCertValidityPeriod ::= SEQUENCE { + * notBeforeTime GeneralizedTime, + * notAfterTime GeneralizedTime + * } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [notBeforeTime] + * @property {string} [notAfterTime] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [new asn1js.GeneralizedTime({ + name: names.notBeforeTime || "" + }), new asn1js.GeneralizedTime({ + name: names.notAfterTime || "" + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["notBeforeTime", "notAfterTime"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, AttCertValidityPeriod.schema({ + names: { + notBeforeTime: "notBeforeTime", + notAfterTime: "notAfterTime" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for AttCertValidityPeriod"); //endregion + //region Get internal properties from parsed schema + + this.notBeforeTime = asn1.result.notBeforeTime.toDate(); + this.notAfterTime = asn1.result.notAfterTime.toDate(); //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Construct and return new ASN.1 schema for this object + return new asn1js.Sequence({ + value: [new asn1js.GeneralizedTime({ + valueDate: this.notBeforeTime + }), new asn1js.GeneralizedTime({ + valueDate: this.notAfterTime + })] + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + return { + notBeforeTime: this.notBeforeTime, + notAfterTime: this.notAfterTime + }; + } //********************************************************************************** + + +} //************************************************************************************** + +/** + * Class from RFC5755 + */ + + +exports.AttCertValidityPeriod = AttCertValidityPeriod; + +class IssuerSerial { + //********************************************************************************** + + /** + * Constructor for IssuerSerial class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {RelativeDistinguishedNames} + * @desc issuer + */ + this.issuer = (0, _pvutils.getParametersValue)(parameters, "issuer", IssuerSerial.defaultValues("issuer")); + /** + * @type {Integer} + * @desc serialNumber + */ + + this.serialNumber = (0, _pvutils.getParametersValue)(parameters, "serialNumber", IssuerSerial.defaultValues("serialNumber")); + if ("issuerUID" in parameters) + /** + * @type {BitString} + * @desc issuerUID + */ + this.issuerUID = (0, _pvutils.getParametersValue)(parameters, "issuerUID", IssuerSerial.defaultValues("issuerUID")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "issuer": + return new _GeneralNames.default(); + + case "serialNumber": + return new asn1js.Integer(); + + case "issuerUID": + return new asn1js.BitString(); + + default: + throw new Error(`Invalid member name for IssuerSerial class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * IssuerSerial ::= SEQUENCE { + * issuer GeneralNames, + * serial CertificateSerialNumber, + * issuerUID UniqueIdentifier OPTIONAL + * } + * + * CertificateSerialNumber ::= INTEGER + * UniqueIdentifier ::= BIT STRING + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [issuer] + * @property {string} [serialNumber] + * @property {string} [issuerUID] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [_GeneralNames.default.schema(names.issuer || {}), new asn1js.Integer({ + name: names.serialNumber || "" + }), new asn1js.BitString({ + optional: true, + name: names.issuerUID || "" + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["issuer", "serialNumber", "issuerUID"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, IssuerSerial.schema({ + names: { + issuer: { + names: { + blockName: "issuer" + } + }, + serialNumber: "serialNumber", + issuerUID: "issuerUID" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for IssuerSerial"); //endregion + //region Get internal properties from parsed schema + + this.issuer = new _GeneralNames.default({ + schema: asn1.result.issuer + }); + this.serialNumber = asn1.result.serialNumber; + if ("issuerUID" in asn1.result) this.issuerUID = asn1.result.issuerUID; //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + const result = new asn1js.Sequence({ + value: [this.issuer.toSchema(), this.serialNumber] + }); + if ("issuerUID" in this) result.valueBlock.value.push(this.issuerUID); //region Construct and return new ASN.1 schema for this object + + return result; //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + const result = { + issuer: this.issuer.toJSON(), + serialNumber: this.serialNumber.toJSON() + }; + if ("issuerUID" in this) result.issuerUID = this.issuerUID.toJSON(); + return result; + } //********************************************************************************** + + +} //************************************************************************************** + +/** + * Class from RFC5755 + */ + + +exports.IssuerSerial = IssuerSerial; + +class AttributeCertificateInfoV1 { + //********************************************************************************** + + /** + * Constructor for AttributeCertificateInfoV1 class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {Number} + * @desc version + */ + this.version = (0, _pvutils.getParametersValue)(parameters, "version", AttributeCertificateInfoV1.defaultValues("version")); + if ("baseCertificateID" in parameters) + /** + * @type {IssuerSerial} + * @desc baseCertificateID + */ + this.baseCertificateID = (0, _pvutils.getParametersValue)(parameters, "baseCertificateID", AttributeCertificateInfoV1.defaultValues("baseCertificateID")); + if ("subjectName" in parameters) + /** + * @type {GeneralNames} + * @desc subjectName + */ + this.subjectName = (0, _pvutils.getParametersValue)(parameters, "subjectName", AttributeCertificateInfoV1.defaultValues("subjectName")); + /** + * @type {GeneralNames} + * @desc issuer + */ + + this.issuer = (0, _pvutils.getParametersValue)(parameters, "issuer", AttributeCertificateInfoV1.defaultValues("issuer")); + /** + * @type {AlgorithmIdentifier} + * @desc signature + */ + + this.signature = (0, _pvutils.getParametersValue)(parameters, "signature", AttributeCertificateInfoV1.defaultValues("signature")); + /** + * @type {Integer} + * @desc serialNumber + */ + + this.serialNumber = (0, _pvutils.getParametersValue)(parameters, "serialNumber", AttributeCertificateInfoV1.defaultValues("serialNumber")); + /** + * @type {AttCertValidityPeriod} + * @desc attrCertValidityPeriod + */ + + this.attrCertValidityPeriod = (0, _pvutils.getParametersValue)(parameters, "attrCertValidityPeriod", AttributeCertificateInfoV1.defaultValues("attrCertValidityPeriod")); + /** + * @type {Array.} + * @desc attributes + */ + + this.attributes = (0, _pvutils.getParametersValue)(parameters, "attributes", AttributeCertificateInfoV1.defaultValues("attributes")); + if ("issuerUniqueID" in parameters) + /** + * @type {BitString} + * @desc issuerUniqueID + */ + this.issuerUniqueID = (0, _pvutils.getParametersValue)(parameters, "issuerUniqueID", AttributeCertificateInfoV1.defaultValues("issuerUniqueID")); + if ("extensions" in parameters) + /** + * @type {Extensions} + * @desc extensions + */ + this.extensions = (0, _pvutils.getParametersValue)(parameters, "extensions", AttributeCertificateInfoV1.defaultValues("extensions")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "version": + return 0; + + case "baseCertificateID": + return new IssuerSerial(); + + case "subjectName": + return new _GeneralNames.default(); + + case "issuer": + return {}; + + case "signature": + return new _AlgorithmIdentifier.default(); + + case "serialNumber": + return new asn1js.Integer(); + + case "attrCertValidityPeriod": + return new AttCertValidityPeriod(); + + case "attributes": + return []; + + case "issuerUniqueID": + return new asn1js.BitString(); + + case "extensions": + return new _Extensions.default(); + + default: + throw new Error(`Invalid member name for AttributeCertificateInfoV1 class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * AttributeCertificateInfo ::= SEQUENCE { + * version Version DEFAULT v1, + * subject CHOICE { + * baseCertificateID [0] IssuerSerial, -- associated with a Public Key Certificate + * subjectName [1] GeneralNames }, -- associated with a name + * issuer GeneralNames, -- CA issuing the attribute certificate + * signature AlgorithmIdentifier, + * serialNumber CertificateSerialNumber, + * attrCertValidityPeriod AttCertValidityPeriod, + * attributes SEQUENCE OF Attribute, + * issuerUniqueID UniqueIdentifier OPTIONAL, + * extensions Extensions OPTIONAL + * } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [issuer] + * @property {string} [serialNumber] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [new asn1js.Integer({ + name: names.version || "" + }), new asn1js.Choice({ + value: [new asn1js.Constructed({ + name: names.baseCertificateID || "", + idBlock: { + tagClass: 3, + tagNumber: 0 // [0] + + }, + value: IssuerSerial.schema().valueBlock.value + }), new asn1js.Constructed({ + name: names.subjectName || "", + idBlock: { + tagClass: 3, + tagNumber: 1 // [2] + + }, + value: _GeneralNames.default.schema().valueBlock.value + })] + }), _GeneralNames.default.schema({ + names: { + blockName: names.issuer || "" + } + }), _AlgorithmIdentifier.default.schema(names.signature || {}), new asn1js.Integer({ + name: names.serialNumber || "" + }), AttCertValidityPeriod.schema(names.attrCertValidityPeriod || {}), new asn1js.Sequence({ + name: names.attributes || "", + value: [new asn1js.Repeated({ + value: _Attribute.default.schema() + })] + }), new asn1js.BitString({ + optional: true, + name: names.issuerUniqueID || "" + }), _Extensions.default.schema(names.extensions || {}, true)] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["version", "baseCertificateID", "subjectName", "issuer", "signature", "serialNumber", "attrCertValidityPeriod", "attributes", "issuerUniqueID", "extensions"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, AttributeCertificateInfoV1.schema({ + names: { + version: "version", + baseCertificateID: "baseCertificateID", + subjectName: "subjectName", + issuer: "issuer", + signature: { + names: { + blockName: "signature" + } + }, + serialNumber: "serialNumber", + attrCertValidityPeriod: { + names: { + blockName: "attrCertValidityPeriod" + } + }, + attributes: "attributes", + issuerUniqueID: "issuerUniqueID", + extensions: { + names: { + blockName: "extensions" + } + } + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for AttributeCertificateInfoV1"); //endregion + //region Get internal properties from parsed schema + + this.version = asn1.result.version.valueBlock.valueDec; + + if ("baseCertificateID" in asn1.result) { + this.baseCertificateID = new IssuerSerial({ + schema: new asn1js.Sequence({ + value: asn1.result.baseCertificateID.valueBlock.value + }) + }); + } + + if ("subjectName" in asn1.result) { + this.subjectName = new _GeneralNames.default({ + schema: new asn1js.Sequence({ + value: asn1.result.subjectName.valueBlock.value + }) + }); + } + + this.issuer = asn1.result.issuer; + this.signature = new _AlgorithmIdentifier.default({ + schema: asn1.result.signature + }); + this.serialNumber = asn1.result.serialNumber; + this.attrCertValidityPeriod = new AttCertValidityPeriod({ + schema: asn1.result.attrCertValidityPeriod + }); + this.attributes = Array.from(asn1.result.attributes.valueBlock.value, element => new _Attribute.default({ + schema: element + })); + if ("issuerUniqueID" in asn1.result) this.issuerUniqueID = asn1.result.issuerUniqueID; + if ("extensions" in asn1.result) this.extensions = new _Extensions.default({ + schema: asn1.result.extensions + }); //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + const result = new asn1js.Sequence({ + value: [new asn1js.Integer({ + value: this.version + })] + }); + + if ("baseCertificateID" in this) { + result.valueBlock.value.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, + tagNumber: 0 // [0] + + }, + value: this.baseCertificateID.toSchema().valueBlock.value + })); + } + + if ("subjectName" in this) { + result.valueBlock.value.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, + tagNumber: 1 // [1] + + }, + value: this.subjectName.toSchema().valueBlock.value + })); + } + + result.valueBlock.value.push(this.issuer.toSchema()); + result.valueBlock.value.push(this.signature.toSchema()); + result.valueBlock.value.push(this.serialNumber); + result.valueBlock.value.push(this.attrCertValidityPeriod.toSchema()); + result.valueBlock.value.push(new asn1js.Sequence({ + value: Array.from(this.attributes, element => element.toSchema()) + })); + if ("issuerUniqueID" in this) result.valueBlock.value.push(this.issuerUniqueID); + if ("extensions" in this) result.valueBlock.value.push(this.extensions.toSchema()); + return result; + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + const result = { + version: this.version + }; + if ("baseCertificateID" in this) result.baseCertificateID = this.baseCertificateID.toJSON(); + if ("subjectName" in this) result.subjectName = this.subjectName.toJSON(); + result.issuer = this.issuer.toJSON(); + result.signature = this.signature.toJSON(); + result.serialNumber = this.serialNumber.toJSON(); + result.attrCertValidityPeriod = this.attrCertValidityPeriod.toJSON(); + result.attributes = Array.from(this.attributes, element => element.toJSON()); + if ("issuerUniqueID" in this) result.issuerUniqueID = this.issuerUniqueID.toJSON(); + if ("extensions" in this) result.extensions = this.extensions.toJSON(); + return result; + } //********************************************************************************** + + +} //************************************************************************************** + +/** + * Class from X.509:1997 + */ + + +exports.AttributeCertificateInfoV1 = AttributeCertificateInfoV1; + +class AttributeCertificateV1 { + //********************************************************************************** + + /** + * Constructor for AttributeCertificateV1 class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {AttributeCertificateInfoV1} + * @desc acinfo + */ + this.acinfo = (0, _pvutils.getParametersValue)(parameters, "acinfo", AttributeCertificateV1.defaultValues("acinfo")); + /** + * @type {AlgorithmIdentifier} + * @desc signatureAlgorithm + */ + + this.signatureAlgorithm = (0, _pvutils.getParametersValue)(parameters, "signatureAlgorithm", AttributeCertificateV1.defaultValues("signatureAlgorithm")); + /** + * @type {BitString} + * @desc signatureValue + */ + + this.signatureValue = (0, _pvutils.getParametersValue)(parameters, "signatureValue", AttributeCertificateV1.defaultValues("signatureValue")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "acinfo": + return new AttributeCertificateInfoV1(); + + case "signatureAlgorithm": + return new _AlgorithmIdentifier.default(); + + case "signatureValue": + return new asn1js.BitString(); + + default: + throw new Error(`Invalid member name for AttributeCertificateV1 class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * AttributeCertificate ::= SEQUENCE { + * acinfo AttributeCertificateInfoV1, + * signatureAlgorithm AlgorithmIdentifier, + * signatureValue BIT STRING + * } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {Object} [acinfo] + * @property {Object} [signatureAlgorithm] + * @property {string} [signatureValue] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [AttributeCertificateInfoV1.schema(names.acinfo || {}), _AlgorithmIdentifier.default.schema(names.signatureAlgorithm || {}), new asn1js.BitString({ + name: names.signatureValue || "" + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["acinfo", "signatureValue", "signatureAlgorithm"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, AttributeCertificateV1.schema({ + names: { + acinfo: { + names: { + blockName: "acinfo" + } + }, + signatureAlgorithm: { + names: { + blockName: "signatureAlgorithm" + } + }, + signatureValue: "signatureValue" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for AttributeCertificateV1"); //endregion + //region Get internal properties from parsed schema + + this.acinfo = new AttributeCertificateInfoV1({ + schema: asn1.result.acinfo + }); + this.signatureAlgorithm = new _AlgorithmIdentifier.default({ + schema: asn1.result.signatureAlgorithm + }); + this.signatureValue = asn1.result.signatureValue; //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + return new asn1js.Sequence({ + value: [this.acinfo.toSchema(), this.signatureAlgorithm.toSchema(), this.signatureValue] + }); + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + return { + acinfo: this.acinfo.toJSON(), + signatureAlgorithm: this.signatureAlgorithm.toJSON(), + signatureValue: this.signatureValue.toJSON() + }; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = AttributeCertificateV1; + +},{"./AlgorithmIdentifier.js":4,"./Attribute.js":6,"./Extensions.js":39,"./GeneralNames.js":41,"asn1js":112,"pvutils":113}],8:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = exports.AttributeCertificateInfoV2 = exports.Holder = exports.V2Form = exports.ObjectDigestInfo = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _GeneralNames = _interopRequireDefault(require("./GeneralNames.js")); + +var _AlgorithmIdentifier = _interopRequireDefault(require("./AlgorithmIdentifier.js")); + +var _Attribute = _interopRequireDefault(require("./Attribute.js")); + +var _Extensions = _interopRequireDefault(require("./Extensions.js")); + +var _AttributeCertificateV = require("./AttributeCertificateV1.js"); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC5755 + */ +class ObjectDigestInfo { + //********************************************************************************** + + /** + * Constructor for ObjectDigestInfo class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {Enumerated} + * @desc digestedObjectType + */ + this.digestedObjectType = (0, _pvutils.getParametersValue)(parameters, "digestedObjectType", ObjectDigestInfo.defaultValues("digestedObjectType")); + if ("otherObjectTypeID" in parameters) + /** + * @type {ObjectIdentifier} + * @desc otherObjectTypeID + */ + this.otherObjectTypeID = (0, _pvutils.getParametersValue)(parameters, "otherObjectTypeID", ObjectDigestInfo.defaultValues("otherObjectTypeID")); + /** + * @type {AlgorithmIdentifier} + * @desc digestAlgorithm + */ + + this.digestAlgorithm = (0, _pvutils.getParametersValue)(parameters, "digestAlgorithm", ObjectDigestInfo.defaultValues("digestAlgorithm")); + /** + * @type {BitString} + * @desc objectDigest + */ + + this.objectDigest = (0, _pvutils.getParametersValue)(parameters, "objectDigest", ObjectDigestInfo.defaultValues("objectDigest")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "digestedObjectType": + return new asn1js.Enumerated(); + + case "otherObjectTypeID": + return new asn1js.ObjectIdentifier(); + + case "digestAlgorithm": + return new _AlgorithmIdentifier.default(); + + case "objectDigest": + return new asn1js.BitString(); + + default: + throw new Error(`Invalid member name for ObjectDigestInfo class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * ObjectDigestInfo ::= SEQUENCE { + * digestedObjectType ENUMERATED { + * publicKey (0), + * publicKeyCert (1), + * otherObjectTypes (2) }, + * -- otherObjectTypes MUST NOT + * -- be used in this profile + * otherObjectTypeID OBJECT IDENTIFIER OPTIONAL, + * digestAlgorithm AlgorithmIdentifier, + * objectDigest BIT STRING + * } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [digestedObjectType] + * @property {string} [otherObjectTypeID] + * @property {string} [digestAlgorithm] + * @property {string} [objectDigest] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [new asn1js.Enumerated({ + name: names.digestedObjectType || "" + }), new asn1js.ObjectIdentifier({ + optional: true, + name: names.otherObjectTypeID || "" + }), _AlgorithmIdentifier.default.schema(names.digestAlgorithm || {}), new asn1js.BitString({ + name: names.objectDigest || "" + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["digestedObjectType", "otherObjectTypeID", "digestAlgorithm", "objectDigest"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, ObjectDigestInfo.schema({ + names: { + digestedObjectType: "digestedObjectType", + otherObjectTypeID: "otherObjectTypeID", + digestAlgorithm: { + names: { + blockName: "digestAlgorithm" + } + }, + objectDigest: "objectDigest" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for ObjectDigestInfo"); //endregion + //region Get internal properties from parsed schema + + this.digestedObjectType = asn1.result.digestedObjectType; + if ("otherObjectTypeID" in asn1.result) this.otherObjectTypeID = asn1.result.otherObjectTypeID; + this.digestAlgorithm = new _AlgorithmIdentifier.default({ + schema: asn1.result.digestAlgorithm + }); + this.objectDigest = asn1.result.objectDigest; //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + const result = new asn1js.Sequence({ + value: [this.digestedObjectType] + }); + if ("otherObjectTypeID" in this) result.value.push(this.otherObjectTypeID); + result.value.push(this.digestAlgorithm.toSchema()); + result.value.push(this.objectDigest); + return result; + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + const result = { + digestedObjectType: this.digestedObjectType.toJSON() + }; + if ("otherObjectTypeID" in this) result.otherObjectTypeID = this.otherObjectTypeID.toJSON(); + result.digestAlgorithm = this.digestAlgorithm.toJSON(); + result.objectDigest = this.objectDigest.toJSON(); + return result; + } //********************************************************************************** + + +} //************************************************************************************** + +/** + * Class from RFC5755 + */ + + +exports.ObjectDigestInfo = ObjectDigestInfo; + +class V2Form { + //********************************************************************************** + + /** + * Constructor for V2Form class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + if ("issuerName" in parameters) + /** + * @type {GeneralNames} + * @desc issuerName + */ + this.issuerName = (0, _pvutils.getParametersValue)(parameters, "issuerName", V2Form.defaultValues("issuerName")); + if ("baseCertificateID" in parameters) + /** + * @type {IssuerSerial} + * @desc baseCertificateID + */ + this.baseCertificateID = (0, _pvutils.getParametersValue)(parameters, "baseCertificateID", V2Form.defaultValues("baseCertificateID")); + if ("objectDigestInfo" in parameters) + /** + * @type {ObjectDigestInfo} + * @desc objectDigestInfo + */ + this.objectDigestInfo = (0, _pvutils.getParametersValue)(parameters, "objectDigestInfo", V2Form.defaultValues("objectDigestInfo")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "issuerName": + return new _GeneralNames.default(); + + case "baseCertificateID": + return new _AttributeCertificateV.IssuerSerial(); + + case "objectDigestInfo": + return new ObjectDigestInfo(); + + default: + throw new Error(`Invalid member name for V2Form class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * V2Form ::= SEQUENCE { + * issuerName GeneralNames OPTIONAL, + * baseCertificateID [0] IssuerSerial OPTIONAL, + * objectDigestInfo [1] ObjectDigestInfo OPTIONAL + * -- issuerName MUST be present in this profile + * -- baseCertificateID and objectDigestInfo MUST NOT + * -- be present in this profile + * } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [issuerName] + * @property {string} [baseCertificateID] + * @property {string} [objectDigestInfo] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [_GeneralNames.default.schema({ + names: { + blockName: names.issuerName + } + }, true), new asn1js.Constructed({ + optional: true, + name: names.baseCertificateID || "", + idBlock: { + tagClass: 3, + tagNumber: 0 // [0] + + }, + value: _AttributeCertificateV.IssuerSerial.schema().valueBlock.value + }), new asn1js.Constructed({ + optional: true, + name: names.objectDigestInfo || "", + idBlock: { + tagClass: 3, + tagNumber: 1 // [1] + + }, + value: ObjectDigestInfo.schema().valueBlock.value + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["issuerName", "baseCertificateID", "objectDigestInfo"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, V2Form.schema({ + names: { + issuerName: "issuerName", + baseCertificateID: "baseCertificateID", + objectDigestInfo: "objectDigestInfo" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for V2Form"); //endregion + //region Get internal properties from parsed schema + + if ("issuerName" in asn1.result) this.issuerName = new _GeneralNames.default({ + schema: asn1.result.issuerName + }); + + if ("baseCertificateID" in asn1.result) { + this.baseCertificateID = new _AttributeCertificateV.IssuerSerial({ + schema: new asn1js.Sequence({ + value: asn1.result.baseCertificateID.valueBlock.value + }) + }); + } + + if ("objectDigestInfo" in asn1.result) { + this.objectDigestInfo = new ObjectDigestInfo({ + schema: new asn1js.Sequence({ + value: asn1.result.objectDigestInfo.valueBlock.value + }) + }); + } //endregion + + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + const result = new asn1js.Sequence(); + if ("issuerName" in this) result.valueBlock.value.push(this.issuerName.toSchema()); + + if ("baseCertificateID" in this) { + result.valueBlock.value.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, + tagNumber: 0 // [0] + + }, + value: this.baseCertificateID.toSchema().valueBlock.value + })); + } + + if ("objectDigestInfo" in this) { + result.valueBlock.value.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, + tagNumber: 1 // [1] + + }, + value: this.objectDigestInfo.toSchema().valueBlock.value + })); + } //region Construct and return new ASN.1 schema for this object + + + return result; //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + const result = {}; + if ("issuerName" in this) result.issuerName = this.issuerName.toJSON(); + if ("baseCertificateID" in this) result.baseCertificateID = this.baseCertificateID.toJSON(); + if ("objectDigestInfo" in this) result.objectDigestInfo = this.objectDigestInfo.toJSON(); + return result; + } //********************************************************************************** + + +} //************************************************************************************** + +/** + * Class from RFC5755 + */ + + +exports.V2Form = V2Form; + +class Holder { + //********************************************************************************** + + /** + * Constructor for Holder class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + if ("baseCertificateID" in parameters) + /** + * @type {IssuerSerial} + * @desc baseCertificateID + */ + this.baseCertificateID = (0, _pvutils.getParametersValue)(parameters, "baseCertificateID", Holder.defaultValues("baseCertificateID")); + if ("entityName" in parameters) + /** + * @type {GeneralNames} + * @desc entityName + */ + this.entityName = (0, _pvutils.getParametersValue)(parameters, "entityName", Holder.defaultValues("entityName")); + if ("objectDigestInfo" in parameters) + /** + * @type {ObjectDigestInfo} + * @desc objectDigestInfo + */ + this.objectDigestInfo = (0, _pvutils.getParametersValue)(parameters, "objectDigestInfo", Holder.defaultValues("objectDigestInfo")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "baseCertificateID": + return new _AttributeCertificateV.IssuerSerial(); + + case "entityName": + return new _GeneralNames.default(); + + case "objectDigestInfo": + return new ObjectDigestInfo(); + + default: + throw new Error(`Invalid member name for Holder class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * Holder ::= SEQUENCE { + * baseCertificateID [0] IssuerSerial OPTIONAL, + * -- the issuer and serial number of + * -- the holder's Public Key Certificate + * entityName [1] GeneralNames OPTIONAL, + * -- the name of the claimant or role + * objectDigestInfo [2] ObjectDigestInfo OPTIONAL + * -- used to directly authenticate the holder, + * -- for example, an executable + * } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [baseCertificateID] + * @property {string} [entityName] + * @property {string} [objectDigestInfo] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [new asn1js.Constructed({ + optional: true, + name: names.baseCertificateID || "", + idBlock: { + tagClass: 3, + tagNumber: 0 // [0] + + }, + value: _AttributeCertificateV.IssuerSerial.schema().valueBlock.value + }), new asn1js.Constructed({ + optional: true, + name: names.entityName || "", + idBlock: { + tagClass: 3, + tagNumber: 1 // [2] + + }, + value: _GeneralNames.default.schema().valueBlock.value + }), new asn1js.Constructed({ + optional: true, + name: names.objectDigestInfo || "", + idBlock: { + tagClass: 3, + tagNumber: 2 // [2] + + }, + value: ObjectDigestInfo.schema().valueBlock.value + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["baseCertificateID", "entityName", "objectDigestInfo"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, Holder.schema({ + names: { + baseCertificateID: "baseCertificateID", + entityName: "entityName", + objectDigestInfo: "objectDigestInfo" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for Holder"); //endregion + //region Get internal properties from parsed schema + + if ("baseCertificateID" in asn1.result) { + this.baseCertificateID = new _AttributeCertificateV.IssuerSerial({ + schema: new asn1js.Sequence({ + value: asn1.result.baseCertificateID.valueBlock.value + }) + }); + } + + if ("entityName" in asn1.result) { + this.entityName = new _GeneralNames.default({ + schema: new asn1js.Sequence({ + value: asn1.result.entityName.valueBlock.value + }) + }); + } + + if ("objectDigestInfo" in asn1.result) { + this.objectDigestInfo = new ObjectDigestInfo({ + schema: new asn1js.Sequence({ + value: asn1.result.objectDigestInfo.valueBlock.value + }) + }); + } //endregion + + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + const result = new asn1js.Sequence(); + + if ("baseCertificateID" in this) { + result.valueBlock.value.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, + tagNumber: 0 // [0] + + }, + value: this.baseCertificateID.toSchema().valueBlock.value + })); + } + + if ("entityName" in this) { + result.valueBlock.value.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, + tagNumber: 1 // [1] + + }, + value: this.entityName.toSchema().valueBlock.value + })); + } + + if ("objectDigestInfo" in this) { + result.valueBlock.value.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, + tagNumber: 2 // [2] + + }, + value: this.objectDigestInfo.toSchema().valueBlock.value + })); + } + + return result; + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + const result = {}; + if ("baseCertificateID" in this) result.baseCertificateID = this.baseCertificateID.toJSON(); + if ("entityName" in this) result.entityName = this.entityName.toJSON(); + if ("objectDigestInfo" in this) result.objectDigestInfo = this.objectDigestInfo.toJSON(); + return result; + } //********************************************************************************** + + +} //************************************************************************************** + +/** + * Class from RFC5755 + */ + + +exports.Holder = Holder; + +class AttributeCertificateInfoV2 { + //********************************************************************************** + + /** + * Constructor for AttributeCertificateInfoV2 class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {Number} + * @desc version + */ + this.version = (0, _pvutils.getParametersValue)(parameters, "version", AttributeCertificateInfoV2.defaultValues("version")); + /** + * @type {Holder} + * @desc holder + */ + + this.holder = (0, _pvutils.getParametersValue)(parameters, "holder", AttributeCertificateInfoV2.defaultValues("holder")); + /** + * @type {GeneralNames|V2Form} + * @desc issuer + */ + + this.issuer = (0, _pvutils.getParametersValue)(parameters, "issuer", AttributeCertificateInfoV2.defaultValues("issuer")); + /** + * @type {AlgorithmIdentifier} + * @desc signature + */ + + this.signature = (0, _pvutils.getParametersValue)(parameters, "signature", AttributeCertificateInfoV2.defaultValues("signature")); + /** + * @type {Integer} + * @desc serialNumber + */ + + this.serialNumber = (0, _pvutils.getParametersValue)(parameters, "serialNumber", AttributeCertificateInfoV2.defaultValues("serialNumber")); + /** + * @type {AttCertValidityPeriod} + * @desc attrCertValidityPeriod + */ + + this.attrCertValidityPeriod = (0, _pvutils.getParametersValue)(parameters, "attrCertValidityPeriod", AttributeCertificateInfoV2.defaultValues("attrCertValidityPeriod")); + /** + * @type {Array.} + * @desc attributes + */ + + this.attributes = (0, _pvutils.getParametersValue)(parameters, "attributes", AttributeCertificateInfoV2.defaultValues("attributes")); + if ("issuerUniqueID" in parameters) + /** + * @type {BitString} + * @desc issuerUniqueID + */ + this.issuerUniqueID = (0, _pvutils.getParametersValue)(parameters, "issuerUniqueID", AttributeCertificateInfoV2.defaultValues("issuerUniqueID")); + if ("extensions" in parameters) + /** + * @type {Extensions} + * @desc extensions + */ + this.extensions = (0, _pvutils.getParametersValue)(parameters, "extensions", AttributeCertificateInfoV2.defaultValues("extensions")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "version": + return 1; + + case "holder": + return new Holder(); + + case "issuer": + return {}; + + case "signature": + return new _AlgorithmIdentifier.default(); + + case "serialNumber": + return new asn1js.Integer(); + + case "attrCertValidityPeriod": + return new _AttributeCertificateV.AttCertValidityPeriod(); + + case "attributes": + return []; + + case "issuerUniqueID": + return new asn1js.BitString(); + + case "extensions": + return new _Extensions.default(); + + default: + throw new Error(`Invalid member name for AttributeCertificateInfoV2 class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * AttributeCertificateInfoV2 ::= SEQUENCE { + * version AttCertVersion, -- version is v2 + * holder Holder, + * issuer AttCertIssuer, + * signature AlgorithmIdentifier, + * serialNumber CertificateSerialNumber, + * attrCertValidityPeriod AttCertValidityPeriod, + * attributes SEQUENCE OF Attribute, + * issuerUniqueID UniqueIdentifier OPTIONAL, + * extensions Extensions OPTIONAL + * } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [issuer] + * @property {string} [serialNumber] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [new asn1js.Integer({ + name: names.version || "" + }), Holder.schema(names.holder || {}), new asn1js.Choice({ + value: [_GeneralNames.default.schema({ + names: { + blockName: names.issuer || "" + } + }), new asn1js.Constructed({ + name: names.issuer || "", + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: V2Form.schema().valueBlock.value + })] + }), _AlgorithmIdentifier.default.schema(names.signature || {}), new asn1js.Integer({ + name: names.serialNumber || "" + }), _AttributeCertificateV.AttCertValidityPeriod.schema(names.attrCertValidityPeriod || {}), new asn1js.Sequence({ + name: names.attributes || "", + value: [new asn1js.Repeated({ + value: _Attribute.default.schema() + })] + }), new asn1js.BitString({ + optional: true, + name: names.issuerUniqueID || "" + }), _Extensions.default.schema(names.extensions || {}, true)] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["version", "holder", "issuer", "signature", "serialNumber", "attrCertValidityPeriod", "attributes", "issuerUniqueID", "extensions"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, AttributeCertificateInfoV2.schema({ + names: { + version: "version", + holder: { + names: { + blockName: "holder" + } + }, + issuer: "issuer", + signature: { + names: { + blockName: "signature" + } + }, + serialNumber: "serialNumber", + attrCertValidityPeriod: { + names: { + blockName: "attrCertValidityPeriod" + } + }, + attributes: "attributes", + issuerUniqueID: "issuerUniqueID", + extensions: { + names: { + blockName: "extensions" + } + } + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for AttributeCertificateInfoV2"); //endregion + //region Get internal properties from parsed schema + + this.version = asn1.result.version.valueBlock.valueDec; + this.holder = new Holder({ + schema: asn1.result.holder + }); + + switch (asn1.result.issuer.idBlock.tagClass) { + case 3: + // V2Form + this.issuer = new V2Form({ + schema: new asn1js.Sequence({ + value: asn1.result.issuer.valueBlock.value + }) + }); + break; + + case 1: // GeneralNames (should not be used) + + default: + throw new Error("Incorect value for 'issuer' in AttributeCertificateInfoV2"); + } + + this.signature = new _AlgorithmIdentifier.default({ + schema: asn1.result.signature + }); + this.serialNumber = asn1.result.serialNumber; + this.attrCertValidityPeriod = new _AttributeCertificateV.AttCertValidityPeriod({ + schema: asn1.result.attrCertValidityPeriod + }); + this.attributes = Array.from(asn1.result.attributes.valueBlock.value, element => new _Attribute.default({ + schema: element + })); + if ("issuerUniqueID" in asn1.result) this.issuerUniqueID = asn1.result.issuerUniqueID; + if ("extensions" in asn1.result) this.extensions = new _Extensions.default({ + schema: asn1.result.extensions + }); //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + const result = new asn1js.Sequence({ + value: [new asn1js.Integer({ + value: this.version + }), this.holder.toSchema(), new asn1js.Constructed({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: this.issuer.toSchema().valueBlock.value + }), this.signature.toSchema(), this.serialNumber, this.attrCertValidityPeriod.toSchema(), new asn1js.Sequence({ + value: Array.from(this.attributes, element => element.toSchema()) + })] + }); + if ("issuerUniqueID" in this) result.valueBlock.value.push(this.issuerUniqueID); + if ("extensions" in this) result.valueBlock.value.push(this.extensions.toSchema()); + return result; + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + const result = { + version: this.version, + holder: this.holder.toJSON(), + issuer: this.issuer.toJSON(), + signature: this.signature.toJSON(), + serialNumber: this.serialNumber.toJSON(), + attrCertValidityPeriod: this.attrCertValidityPeriod.toJSON(), + attributes: Array.from(this.attributes, element => element.toJSON()) + }; + if ("issuerUniqueID" in this) result.issuerUniqueID = this.issuerUniqueID.toJSON(); + if ("extensions" in this) result.extensions = this.extensions.toJSON(); + return result; + } //********************************************************************************** + + +} //************************************************************************************** + +/** + * Class from RFC5755 + */ + + +exports.AttributeCertificateInfoV2 = AttributeCertificateInfoV2; + +class AttributeCertificateV2 { + //********************************************************************************** + + /** + * Constructor for AttributeCertificateV2 class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {AttributeCertificateInfoV2} + * @desc acinfo + */ + this.acinfo = (0, _pvutils.getParametersValue)(parameters, "acinfo", AttributeCertificateV2.defaultValues("acinfo")); + /** + * @type {AlgorithmIdentifier} + * @desc signatureAlgorithm + */ + + this.signatureAlgorithm = (0, _pvutils.getParametersValue)(parameters, "signatureAlgorithm", AttributeCertificateV2.defaultValues("signatureAlgorithm")); + /** + * @type {BitString} + * @desc signatureValue + */ + + this.signatureValue = (0, _pvutils.getParametersValue)(parameters, "signatureValue", AttributeCertificateV2.defaultValues("signatureValue")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "acinfo": + return new AttributeCertificateInfoV2(); + + case "signatureAlgorithm": + return new _AlgorithmIdentifier.default(); + + case "signatureValue": + return new asn1js.BitString(); + + default: + throw new Error(`Invalid member name for AttributeCertificateV2 class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * AttributeCertificate ::= SEQUENCE { + * acinfo AttributeCertificateInfoV2, + * signatureAlgorithm AlgorithmIdentifier, + * signatureValue BIT STRING + * } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {Object} [acinfo] + * @property {Object} [signatureAlgorithm] + * @property {string} [signatureValue] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [AttributeCertificateInfoV2.schema(names.acinfo || {}), _AlgorithmIdentifier.default.schema(names.signatureAlgorithm || {}), new asn1js.BitString({ + name: names.signatureValue || "" + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["acinfo", "signatureAlgorithm", "signatureValue"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, AttributeCertificateV2.schema({ + names: { + acinfo: { + names: { + blockName: "acinfo" + } + }, + signatureAlgorithm: { + names: { + blockName: "signatureAlgorithm" + } + }, + signatureValue: "signatureValue" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for AttributeCertificateV2"); //endregion + //region Get internal properties from parsed schema + + this.acinfo = new AttributeCertificateInfoV2({ + schema: asn1.result.acinfo + }); + this.signatureAlgorithm = new _AlgorithmIdentifier.default({ + schema: asn1.result.signatureAlgorithm + }); + this.signatureValue = asn1.result.signatureValue; //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + return new asn1js.Sequence({ + value: [this.acinfo.toSchema(), this.signatureAlgorithm.toSchema(), this.signatureValue] + }); + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + return { + acinfo: this.acinfo.toJSON(), + signatureAlgorithm: this.signatureAlgorithm.toJSON(), + signatureValue: this.signatureValue.toJSON() + }; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = AttributeCertificateV2; + +},{"./AlgorithmIdentifier.js":4,"./Attribute.js":6,"./AttributeCertificateV1.js":7,"./Extensions.js":39,"./GeneralNames.js":41,"asn1js":112,"pvutils":113}],9:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _common = require("./common.js"); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC5280 + */ +class AttributeTypeAndValue { + //********************************************************************************** + + /** + * Constructor for AttributeTypeAndValue class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {string} + * @desc type + */ + this.type = (0, _pvutils.getParametersValue)(parameters, "type", AttributeTypeAndValue.defaultValues("type")); + /** + * @type {Object} + * @desc Value of the AttributeTypeAndValue class + */ + + this.value = (0, _pvutils.getParametersValue)(parameters, "value", AttributeTypeAndValue.defaultValues("value")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "type": + return ""; + + case "value": + return {}; + + default: + throw new Error(`Invalid member name for AttributeTypeAndValue class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * AttributeTypeAndValue ::= Sequence { + * type AttributeType, + * value AttributeValue } + * + * AttributeType ::= OBJECT IDENTIFIER + * + * AttributeValue ::= ANY -- DEFINED BY AttributeType + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] Name for entire block + * @property {string} [type] Name for "type" element + * @property {string} [value] Name for "value" element + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [new asn1js.ObjectIdentifier({ + name: names.type || "" + }), new asn1js.Any({ + name: names.value || "" + })] + }); + } //********************************************************************************** + + + static blockName() { + return "AttributeTypeAndValue"; + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["type", "typeValue"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, AttributeTypeAndValue.schema({ + names: { + type: "type", + value: "typeValue" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for AttributeTypeAndValue"); //endregion + //region Get internal properties from parsed schema + + this.type = asn1.result.type.valueBlock.toString(); // noinspection JSUnresolvedVariable + + this.value = asn1.result.typeValue; //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Construct and return new ASN.1 schema for this object + return new asn1js.Sequence({ + value: [new asn1js.ObjectIdentifier({ + value: this.type + }), this.value] + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + const _object = { + type: this.type + }; + if (Object.keys(this.value).length !== 0) _object.value = this.value.toJSON();else _object.value = this.value; + return _object; + } //********************************************************************************** + + /** + * Compare two AttributeTypeAndValue values, or AttributeTypeAndValue with ArrayBuffer value + * @param {(AttributeTypeAndValue|ArrayBuffer)} compareTo The value compare to current + * @returns {boolean} + */ + + + isEqual(compareTo) { + const stringBlockNames = [asn1js.Utf8String.blockName(), asn1js.BmpString.blockName(), asn1js.UniversalString.blockName(), asn1js.NumericString.blockName(), asn1js.PrintableString.blockName(), asn1js.TeletexString.blockName(), asn1js.VideotexString.blockName(), asn1js.IA5String.blockName(), asn1js.GraphicString.blockName(), asn1js.VisibleString.blockName(), asn1js.GeneralString.blockName(), asn1js.CharacterString.blockName()]; + + if (compareTo.constructor.blockName() === AttributeTypeAndValue.blockName()) { + if (this.type !== compareTo.type) return false; //region Check we do have both strings + + let isString = false; + const thisName = this.value.constructor.blockName(); + + if (thisName === compareTo.value.constructor.blockName()) { + for (var _i = 0, _stringBlockNames = stringBlockNames; _i < _stringBlockNames.length; _i++) { + const name = _stringBlockNames[_i]; + + if (thisName === name) { + isString = true; + break; + } + } + } //endregion + + + if (isString) { + const value1 = (0, _common.stringPrep)(this.value.valueBlock.value); + const value2 = (0, _common.stringPrep)(compareTo.value.valueBlock.value); + if (value1.localeCompare(value2) !== 0) return false; + } else // Comparing as two ArrayBuffers + { + if ((0, _pvutils.isEqualBuffer)(this.value.valueBeforeDecode, compareTo.value.valueBeforeDecode) === false) return false; + } + + return true; + } + + if (compareTo instanceof ArrayBuffer) return (0, _pvutils.isEqualBuffer)(this.value.valueBeforeDecode, compareTo); + return false; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = AttributeTypeAndValue; + +},{"./common.js":110,"asn1js":112,"pvutils":113}],10:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _ContentInfo = _interopRequireDefault(require("./ContentInfo.js")); + +var _SafeContents = _interopRequireDefault(require("./SafeContents.js")); + +var _EnvelopedData = _interopRequireDefault(require("./EnvelopedData.js")); + +var _EncryptedData = _interopRequireDefault(require("./EncryptedData.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); } + +function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } + +function _iterableToArrayLimit(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } + +function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } + +//************************************************************************************** + +/** + * Class from RFC7292 + */ +class AuthenticatedSafe { + //********************************************************************************** + + /** + * Constructor for AuthenticatedSafe class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {Array.} + * @desc safeContents + */ + this.safeContents = (0, _pvutils.getParametersValue)(parameters, "safeContents", AuthenticatedSafe.defaultValues("safeContents")); + if ("parsedValue" in parameters) + /** + * @type {*} + * @desc parsedValue + */ + this.parsedValue = (0, _pvutils.getParametersValue)(parameters, "parsedValue", AuthenticatedSafe.defaultValues("parsedValue")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "safeContents": + return []; + + case "parsedValue": + return {}; + + default: + throw new Error(`Invalid member name for AuthenticatedSafe class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + + + static compareWithDefault(memberName, memberValue) { + switch (memberName) { + case "safeContents": + return memberValue.length === 0; + + case "parsedValue": + return memberValue instanceof Object && Object.keys(memberValue).length === 0; + + default: + throw new Error(`Invalid member name for AuthenticatedSafe class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * AuthenticatedSafe ::= SEQUENCE OF ContentInfo + * -- Data if unencrypted + * -- EncryptedData if password-encrypted + * -- EnvelopedData if public key-encrypted + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [contentInfos] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [new asn1js.Repeated({ + name: names.contentInfos || "", + value: _ContentInfo.default.schema() + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["contentInfos"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, AuthenticatedSafe.schema({ + names: { + contentInfos: "contentInfos" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for AuthenticatedSafe"); //endregion + //region Get internal properties from parsed schema + + this.safeContents = Array.from(asn1.result.contentInfos, element => new _ContentInfo.default({ + schema: element + })); //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Construct and return new ASN.1 schema for this object + return new asn1js.Sequence({ + value: Array.from(this.safeContents, element => element.toSchema()) + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + return { + safeContents: Array.from(this.safeContents, element => element.toJSON()) + }; + } //********************************************************************************** + + + parseInternalValues(parameters) { + //region Check input data from "parameters" + if (parameters instanceof Object === false) return Promise.reject("The \"parameters\" must has \"Object\" type"); + if ("safeContents" in parameters === false) return Promise.reject("Absent mandatory parameter \"safeContents\""); + if (parameters.safeContents instanceof Array === false) return Promise.reject("The \"parameters.safeContents\" must has \"Array\" type"); + if (parameters.safeContents.length !== this.safeContents.length) return Promise.reject("Length of \"parameters.safeContents\" must be equal to \"this.safeContents.length\""); //endregion + //region Initial variables + + let sequence = Promise.resolve(); //endregion + //region Create value for "this.parsedValue.authenticatedSafe" + + this.parsedValue = { + safeContents: [] + }; + var _iteratorNormalCompletion = true; + var _didIteratorError = false; + var _iteratorError = undefined; + + try { + for (var _iterator = this.safeContents.entries()[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { + const _step$value = _slicedToArray(_step.value, 2), + index = _step$value[0], + content = _step$value[1]; + + switch (content.contentType) { + //region data + case "1.2.840.113549.1.7.1": + { + //region Check that we do have OCTETSTRING as "content" + if (content.content instanceof asn1js.OctetString === false) return Promise.reject("Wrong type of \"this.safeContents[j].content\""); //endregion + //region Check we have "constructive encoding" for AuthSafe content + + let authSafeContent = new ArrayBuffer(0); + + if (content.content.valueBlock.isConstructed) { + var _iteratorNormalCompletion2 = true; + var _didIteratorError2 = false; + var _iteratorError2 = undefined; + + try { + for (var _iterator2 = content.content.valueBlock.value[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { + const contentValue = _step2.value; + authSafeContent = (0, _pvutils.utilConcatBuf)(authSafeContent, contentValue.valueBlock.valueHex); + } + } catch (err) { + _didIteratorError2 = true; + _iteratorError2 = err; + } finally { + try { + if (!_iteratorNormalCompletion2 && _iterator2.return != null) { + _iterator2.return(); + } + } finally { + if (_didIteratorError2) { + throw _iteratorError2; + } + } + } + } else authSafeContent = content.content.valueBlock.valueHex; //endregion + //region Parse internal ASN.1 data + + + const asn1 = asn1js.fromBER(authSafeContent); + if (asn1.offset === -1) return Promise.reject("Error during parsing of ASN.1 data inside \"content.content\""); //endregion + //region Finilly initialize initial values of "SafeContents" type + + this.parsedValue.safeContents.push({ + privacyMode: 0, + // No privacy, clear data + value: new _SafeContents.default({ + schema: asn1.result + }) + }); //endregion + } + break; + //endregion + //region envelopedData + + case "1.2.840.113549.1.7.3": + { + //region Initial variables + const cmsEnveloped = new _EnvelopedData.default({ + schema: content.content + }); //endregion + //region Check mandatory parameters + + if ("recipientCertificate" in parameters.safeContents[index] === false) return Promise.reject("Absent mandatory parameter \"recipientCertificate\" in \"parameters.safeContents[j]\""); + const recipientCertificate = parameters.safeContents[index].recipientCertificate; + if ("recipientKey" in parameters.safeContents[index] === false) return Promise.reject("Absent mandatory parameter \"recipientKey\" in \"parameters.safeContents[j]\""); // noinspection JSUnresolvedVariable + + const recipientKey = parameters.safeContents[index].recipientKey; //endregion + //region Decrypt CMS EnvelopedData using first recipient information + + sequence = sequence.then(() => cmsEnveloped.decrypt(0, { + recipientCertificate, + recipientPrivateKey: recipientKey + })); + sequence = sequence.then( + /** + * @param {ArrayBuffer} result + */ + result => { + const asn1 = asn1js.fromBER(result); + if (asn1.offset === -1) return Promise.reject("Error during parsing of decrypted data"); + this.parsedValue.safeContents.push({ + privacyMode: 2, + // Public-key privacy mode + value: new _SafeContents.default({ + schema: asn1.result + }) + }); + return Promise.resolve(); + }); //endregion + } + break; + //endregion + //region encryptedData + + case "1.2.840.113549.1.7.6": + { + //region Initial variables + const cmsEncrypted = new _EncryptedData.default({ + schema: content.content + }); //endregion + //region Check mandatory parameters + + if ("password" in parameters.safeContents[index] === false) return Promise.reject("Absent mandatory parameter \"password\" in \"parameters.safeContents[j]\""); + const password = parameters.safeContents[index].password; //endregion + //region Decrypt CMS EncryptedData using password + + sequence = sequence.then(() => cmsEncrypted.decrypt({ + password + }), error => Promise.reject(error)); //endregion + //region Initialize internal data + + sequence = sequence.then( + /** + * @param {ArrayBuffer} result + */ + result => { + const asn1 = asn1js.fromBER(result); + if (asn1.offset === -1) return Promise.reject("Error during parsing of decrypted data"); + this.parsedValue.safeContents.push({ + privacyMode: 1, + // Password-based privacy mode + value: new _SafeContents.default({ + schema: asn1.result + }) + }); + return Promise.resolve(); + }, error => Promise.reject(error)); //endregion + } + break; + //endregion + //region default + + default: + throw new Error(`Unknown "contentType" for AuthenticatedSafe: " ${content.contentType}`); + //endregion + } + } //endregion + + } catch (err) { + _didIteratorError = true; + _iteratorError = err; + } finally { + try { + if (!_iteratorNormalCompletion && _iterator.return != null) { + _iterator.return(); + } + } finally { + if (_didIteratorError) { + throw _iteratorError; + } + } + } + + return sequence; + } //********************************************************************************** + + + makeInternalValues(parameters) { + //region Check data in "parsedValue" + if ("parsedValue" in this === false) return Promise.reject("Please run \"parseValues\" first or add \"parsedValue\" manually"); + if (this.parsedValue instanceof Object === false) return Promise.reject("The \"this.parsedValue\" must has \"Object\" type"); + if (this.parsedValue.safeContents instanceof Array === false) return Promise.reject("The \"this.parsedValue.safeContents\" must has \"Array\" type"); //endregion + //region Check input data from "parameters" + + if (parameters instanceof Object === false) return Promise.reject("The \"parameters\" must has \"Object\" type"); + if ("safeContents" in parameters === false) return Promise.reject("Absent mandatory parameter \"safeContents\""); + if (parameters.safeContents instanceof Array === false) return Promise.reject("The \"parameters.safeContents\" must has \"Array\" type"); + if (parameters.safeContents.length !== this.parsedValue.safeContents.length) return Promise.reject("Length of \"parameters.safeContents\" must be equal to \"this.parsedValue.safeContents\""); //endregion + //region Initial variables + + let sequence = Promise.resolve(); //endregion + //region Create internal values from already parsed values + + this.safeContents = []; + var _iteratorNormalCompletion3 = true; + var _didIteratorError3 = false; + var _iteratorError3 = undefined; + + try { + for (var _iterator3 = this.parsedValue.safeContents.entries()[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) { + const _step3$value = _slicedToArray(_step3.value, 2), + index = _step3$value[0], + content = _step3$value[1]; + + //region Check current "content" value + if ("privacyMode" in content === false) return Promise.reject("The \"privacyMode\" is a mandatory parameter for \"content\""); + if ("value" in content === false) return Promise.reject("The \"value\" is a mandatory parameter for \"content\""); + if (content.value instanceof _SafeContents.default === false) return Promise.reject("The \"content.value\" must has \"SafeContents\" type"); //endregion + + switch (content.privacyMode) { + //region No privacy + case 0: + { + const contentBuffer = content.value.toSchema().toBER(false); + sequence = sequence.then(() => { + this.safeContents.push(new _ContentInfo.default({ + contentType: "1.2.840.113549.1.7.1", + content: new asn1js.OctetString({ + valueHex: contentBuffer + }) + })); + }); + } + break; + //endregion + //region Privacy with password + + case 1: + { + //region Initial variables + const cmsEncrypted = new _EncryptedData.default(); + const currentParameters = parameters.safeContents[index]; + currentParameters.contentToEncrypt = content.value.toSchema().toBER(false); //endregion + //region Encrypt CMS EncryptedData using password + + sequence = sequence.then(() => cmsEncrypted.encrypt(currentParameters), error => Promise.reject(error)); //endregion + //region Store result content in CMS_CONTENT_INFO type + + sequence = sequence.then(() => { + this.safeContents.push(new _ContentInfo.default({ + contentType: "1.2.840.113549.1.7.6", + content: cmsEncrypted.toSchema() + })); + }, error => Promise.reject(error)); //endregion + } + break; + //endregion + //region Privacy with public key + + case 2: + { + //region Initial variables + const cmsEnveloped = new _EnvelopedData.default(); + const contentToEncrypt = content.value.toSchema().toBER(false); //endregion + //region Check mandatory parameters + + if ("encryptingCertificate" in parameters.safeContents[index] === false) return Promise.reject("Absent mandatory parameter \"encryptingCertificate\" in \"parameters.safeContents[i]\""); + if ("encryptionAlgorithm" in parameters.safeContents[index] === false) return Promise.reject("Absent mandatory parameter \"encryptionAlgorithm\" in \"parameters.safeContents[i]\""); + + switch (true) { + case parameters.safeContents[index].encryptionAlgorithm.name.toLowerCase() === "aes-cbc": + case parameters.safeContents[index].encryptionAlgorithm.name.toLowerCase() === "aes-gcm": + break; + + default: + return Promise.reject(`Incorrect parameter "encryptionAlgorithm" in "parameters.safeContents[i]": ${parameters.safeContents[index].encryptionAlgorithm}`); + } + + switch (true) { + case parameters.safeContents[index].encryptionAlgorithm.length === 128: + case parameters.safeContents[index].encryptionAlgorithm.length === 192: + case parameters.safeContents[index].encryptionAlgorithm.length === 256: + break; + + default: + return Promise.reject(`Incorrect parameter "encryptionAlgorithm.length" in "parameters.safeContents[i]": ${parameters.safeContents[index].encryptionAlgorithm.length}`); + } //endregion + //region Making correct "encryptionAlgorithm" variable + + + const encryptionAlgorithm = parameters.safeContents[index].encryptionAlgorithm; //endregion + //region Append recipient for enveloped data + + cmsEnveloped.addRecipientByCertificate(parameters.safeContents[index].encryptingCertificate); //endregion + //region Making encryption + + sequence = sequence.then(() => cmsEnveloped.encrypt(encryptionAlgorithm, contentToEncrypt)); + sequence = sequence.then(() => { + this.safeContents.push(new _ContentInfo.default({ + contentType: "1.2.840.113549.1.7.3", + content: cmsEnveloped.toSchema() + })); + }); //endregion + } + break; + //endregion + //region default + + default: + return Promise.reject(`Incorrect value for "content.privacyMode": ${content.privacyMode}`); + //endregion + } + } //endregion + //region Return result of the function + + } catch (err) { + _didIteratorError3 = true; + _iteratorError3 = err; + } finally { + try { + if (!_iteratorNormalCompletion3 && _iterator3.return != null) { + _iterator3.return(); + } + } finally { + if (_didIteratorError3) { + throw _iteratorError3; + } + } + } + + return sequence.then(() => this, error => Promise.reject(`Error during parsing: ${error}`)); //endregion + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = AuthenticatedSafe; + +},{"./ContentInfo.js":26,"./EncryptedData.js":35,"./EnvelopedData.js":36,"./SafeContents.js":96,"asn1js":112,"pvutils":113}],11:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _GeneralName = _interopRequireDefault(require("./GeneralName.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC5280 + */ +class AuthorityKeyIdentifier { + //********************************************************************************** + + /** + * Constructor for AuthorityKeyIdentifier class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + if ("keyIdentifier" in parameters) + /** + * @type {OctetString} + * @desc keyIdentifier + */ + this.keyIdentifier = (0, _pvutils.getParametersValue)(parameters, "keyIdentifier", AuthorityKeyIdentifier.defaultValues("keyIdentifier")); + if ("authorityCertIssuer" in parameters) + /** + * @type {Array.} + * @desc authorityCertIssuer + */ + this.authorityCertIssuer = (0, _pvutils.getParametersValue)(parameters, "authorityCertIssuer", AuthorityKeyIdentifier.defaultValues("authorityCertIssuer")); + if ("authorityCertSerialNumber" in parameters) + /** + * @type {Integer} + * @desc authorityCertIssuer + */ + this.authorityCertSerialNumber = (0, _pvutils.getParametersValue)(parameters, "authorityCertSerialNumber", AuthorityKeyIdentifier.defaultValues("authorityCertSerialNumber")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "keyIdentifier": + return new asn1js.OctetString(); + + case "authorityCertIssuer": + return []; + + case "authorityCertSerialNumber": + return new asn1js.Integer(); + + default: + throw new Error(`Invalid member name for AuthorityKeyIdentifier class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * AuthorityKeyIdentifier OID ::= 2.5.29.35 + * + * AuthorityKeyIdentifier ::= SEQUENCE { + * keyIdentifier [0] KeyIdentifier OPTIONAL, + * authorityCertIssuer [1] GeneralNames OPTIONAL, + * authorityCertSerialNumber [2] CertificateSerialNumber OPTIONAL } + * + * KeyIdentifier ::= OCTET STRING + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [keyIdentifier] + * @property {string} [authorityCertIssuer] + * @property {string} [authorityCertSerialNumber] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [new asn1js.Primitive({ + name: names.keyIdentifier || "", + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + } + }), new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + + }, + value: [new asn1js.Repeated({ + name: names.authorityCertIssuer || "", + value: _GeneralName.default.schema() + })] + }), new asn1js.Primitive({ + name: names.authorityCertSerialNumber || "", + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 2 // [2] + + } + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["keyIdentifier", "authorityCertIssuer", "authorityCertSerialNumber"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, AuthorityKeyIdentifier.schema({ + names: { + keyIdentifier: "keyIdentifier", + authorityCertIssuer: "authorityCertIssuer", + authorityCertSerialNumber: "authorityCertSerialNumber" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for AuthorityKeyIdentifier"); //endregion + //region Get internal properties from parsed schema + + if ("keyIdentifier" in asn1.result) this.keyIdentifier = new asn1js.OctetString({ + valueHex: asn1.result.keyIdentifier.valueBlock.valueHex + }); + if ("authorityCertIssuer" in asn1.result) this.authorityCertIssuer = Array.from(asn1.result.authorityCertIssuer, element => new _GeneralName.default({ + schema: element + })); + if ("authorityCertSerialNumber" in asn1.result) this.authorityCertSerialNumber = new asn1js.Integer({ + valueHex: asn1.result.authorityCertSerialNumber.valueBlock.valueHex + }); //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Create array for output sequence + const outputArray = []; + + if ("keyIdentifier" in this) { + outputArray.push(new asn1js.Primitive({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + valueHex: this.keyIdentifier.valueBlock.valueHex + })); + } + + if ("authorityCertIssuer" in this) { + outputArray.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + + }, + value: Array.from(this.authorityCertIssuer, element => element.toSchema()) + })); + } + + if ("authorityCertSerialNumber" in this) { + outputArray.push(new asn1js.Primitive({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 2 // [2] + + }, + valueHex: this.authorityCertSerialNumber.valueBlock.valueHex + })); + } //endregion + //region Construct and return new ASN.1 schema for this object + + + return new asn1js.Sequence({ + value: outputArray + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + const object = {}; + if ("keyIdentifier" in this) object.keyIdentifier = this.keyIdentifier.toJSON(); + if ("authorityCertIssuer" in this) object.authorityCertIssuer = Array.from(this.authorityCertIssuer, element => element.toJSON()); + if ("authorityCertSerialNumber" in this) object.authorityCertSerialNumber = this.authorityCertSerialNumber.toJSON(); + return object; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = AuthorityKeyIdentifier; + +},{"./GeneralName.js":40,"asn1js":112,"pvutils":113}],12:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC5280 + */ +class BasicConstraints { + //********************************************************************************** + + /** + * Constructor for BasicConstraints class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + * @property {Object} [cA] + * @property {Object} [pathLenConstraint] + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {boolean} + * @desc cA + */ + this.cA = (0, _pvutils.getParametersValue)(parameters, "cA", false); + if ("pathLenConstraint" in parameters) + /** + * @type {number|Integer} + * @desc pathLenConstraint + */ + this.pathLenConstraint = (0, _pvutils.getParametersValue)(parameters, "pathLenConstraint", 0); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "cA": + return false; + + default: + throw new Error(`Invalid member name for BasicConstraints class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * BasicConstraints ::= SEQUENCE { + * cA BOOLEAN DEFAULT FALSE, + * pathLenConstraint INTEGER (0..MAX) OPTIONAL } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [cA] + * @property {string} [pathLenConstraint] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [new asn1js.Boolean({ + optional: true, + name: names.cA || "" + }), new asn1js.Integer({ + optional: true, + name: names.pathLenConstraint || "" + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["cA", "pathLenConstraint"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, BasicConstraints.schema({ + names: { + cA: "cA", + pathLenConstraint: "pathLenConstraint" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for BasicConstraints"); //endregion + //region Get internal properties from parsed schema + + if ("cA" in asn1.result) this.cA = asn1.result.cA.valueBlock.value; + + if ("pathLenConstraint" in asn1.result) { + if (asn1.result.pathLenConstraint.valueBlock.isHexOnly) this.pathLenConstraint = asn1.result.pathLenConstraint;else this.pathLenConstraint = asn1.result.pathLenConstraint.valueBlock.valueDec; + } //endregion + + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Create array for output sequence + const outputArray = []; + if (this.cA !== BasicConstraints.defaultValues("cA")) outputArray.push(new asn1js.Boolean({ + value: this.cA + })); + + if ("pathLenConstraint" in this) { + if (this.pathLenConstraint instanceof asn1js.Integer) outputArray.push(this.pathLenConstraint);else outputArray.push(new asn1js.Integer({ + value: this.pathLenConstraint + })); + } //endregion + //region Construct and return new ASN.1 schema for this object + + + return new asn1js.Sequence({ + value: outputArray + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + const object = {}; + if (this.cA !== BasicConstraints.defaultValues("cA")) object.cA = this.cA; + + if ("pathLenConstraint" in this) { + if (this.pathLenConstraint instanceof asn1js.Integer) object.pathLenConstraint = this.pathLenConstraint.toJSON();else object.pathLenConstraint = this.pathLenConstraint; + } + + return object; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = BasicConstraints; + +},{"asn1js":112,"pvutils":113}],13:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _common = require("./common.js"); + +var _ResponseData = _interopRequireDefault(require("./ResponseData.js")); + +var _AlgorithmIdentifier = _interopRequireDefault(require("./AlgorithmIdentifier.js")); + +var _Certificate = _interopRequireDefault(require("./Certificate.js")); + +var _CertID = _interopRequireDefault(require("./CertID.js")); + +var _RelativeDistinguishedNames = _interopRequireDefault(require("./RelativeDistinguishedNames.js")); + +var _CertificateChainValidationEngine = _interopRequireDefault(require("./CertificateChainValidationEngine.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); } + +function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } + +function _iterableToArrayLimit(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } + +function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } + +//************************************************************************************** + +/** + * Class from RFC6960 + */ +class BasicOCSPResponse { + //********************************************************************************** + + /** + * Constructor for BasicOCSPResponse class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {ResponseData} + * @desc tbsResponseData + */ + this.tbsResponseData = (0, _pvutils.getParametersValue)(parameters, "tbsResponseData", BasicOCSPResponse.defaultValues("tbsResponseData")); + /** + * @type {AlgorithmIdentifier} + * @desc signatureAlgorithm + */ + + this.signatureAlgorithm = (0, _pvutils.getParametersValue)(parameters, "signatureAlgorithm", BasicOCSPResponse.defaultValues("signatureAlgorithm")); + /** + * @type {BitString} + * @desc signature + */ + + this.signature = (0, _pvutils.getParametersValue)(parameters, "signature", BasicOCSPResponse.defaultValues("signature")); + if ("certs" in parameters) + /** + * @type {Array.} + * @desc certs + */ + this.certs = (0, _pvutils.getParametersValue)(parameters, "certs", BasicOCSPResponse.defaultValues("certs")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "tbsResponseData": + return new _ResponseData.default(); + + case "signatureAlgorithm": + return new _AlgorithmIdentifier.default(); + + case "signature": + return new asn1js.BitString(); + + case "certs": + return []; + + default: + throw new Error(`Invalid member name for BasicOCSPResponse class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + + + static compareWithDefault(memberName, memberValue) { + switch (memberName) { + case "type": + { + // noinspection OverlyComplexBooleanExpressionJS + let comparisonResult = _ResponseData.default.compareWithDefault("tbs", memberValue.tbs) && _ResponseData.default.compareWithDefault("responderID", memberValue.responderID) && _ResponseData.default.compareWithDefault("producedAt", memberValue.producedAt) && _ResponseData.default.compareWithDefault("responses", memberValue.responses); + + if ("responseExtensions" in memberValue) comparisonResult = comparisonResult && _ResponseData.default.compareWithDefault("responseExtensions", memberValue.responseExtensions); + return comparisonResult; + } + + case "signatureAlgorithm": + return memberValue.algorithmId === "" && "algorithmParams" in memberValue === false; + + case "signature": + return memberValue.isEqual(BasicOCSPResponse.defaultValues(memberName)); + + case "certs": + return memberValue.length === 0; + + default: + throw new Error(`Invalid member name for BasicOCSPResponse class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * BasicOCSPResponse ::= SEQUENCE { + * tbsResponseData ResponseData, + * signatureAlgorithm AlgorithmIdentifier, + * signature BIT STRING, + * certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [tbsResponseData] + * @property {string} [signatureAlgorithm] + * @property {string} [signature] + * @property {string} [certs] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "BasicOCSPResponse", + value: [_ResponseData.default.schema(names.tbsResponseData || { + names: { + blockName: "BasicOCSPResponse.tbsResponseData" + } + }), _AlgorithmIdentifier.default.schema(names.signatureAlgorithm || { + names: { + blockName: "BasicOCSPResponse.signatureAlgorithm" + } + }), new asn1js.BitString({ + name: names.signature || "BasicOCSPResponse.signature" + }), new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: [new asn1js.Sequence({ + value: [new asn1js.Repeated({ + name: "BasicOCSPResponse.certs", + value: _Certificate.default.schema(names.certs || {}) + })] + })] + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["BasicOCSPResponse.tbsResponseData", "BasicOCSPResponse.signatureAlgorithm", "BasicOCSPResponse.signature", "BasicOCSPResponse.certs"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, BasicOCSPResponse.schema()); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for BasicOCSPResponse"); //endregion + //region Get internal properties from parsed schema + + this.tbsResponseData = new _ResponseData.default({ + schema: asn1.result["BasicOCSPResponse.tbsResponseData"] + }); + this.signatureAlgorithm = new _AlgorithmIdentifier.default({ + schema: asn1.result["BasicOCSPResponse.signatureAlgorithm"] + }); + this.signature = asn1.result["BasicOCSPResponse.signature"]; + if ("BasicOCSPResponse.certs" in asn1.result) this.certs = Array.from(asn1.result["BasicOCSPResponse.certs"], element => new _Certificate.default({ + schema: element + })); //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Create array for output sequence + const outputArray = []; + outputArray.push(this.tbsResponseData.toSchema()); + outputArray.push(this.signatureAlgorithm.toSchema()); + outputArray.push(this.signature); //region Create array of certificates + + if ("certs" in this) { + outputArray.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: [new asn1js.Sequence({ + value: Array.from(this.certs, element => element.toSchema()) + })] + })); + } //endregion + //endregion + //region Construct and return new ASN.1 schema for this object + + + return new asn1js.Sequence({ + value: outputArray + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + const _object = { + tbsResponseData: this.tbsResponseData.toJSON(), + signatureAlgorithm: this.signatureAlgorithm.toJSON(), + signature: this.signature.toJSON() + }; + if ("certs" in this) _object.certs = Array.from(this.certs, element => element.toJSON()); + return _object; + } //********************************************************************************** + + /** + * Get OCSP response status for specific certificate + * @param {Certificate} certificate Certificate to be checked + * @param {Certificate} issuerCertificate Certificate of issuer for certificate to be checked + * @returns {Promise} + */ + + + getCertificateStatus(certificate, issuerCertificate) { + //region Initial variables + let sequence = Promise.resolve(); + const result = { + isForCertificate: false, + status: 2 // 0 = good, 1 = revoked, 2 = unknown + + }; + const hashesObject = {}; + const certIDs = []; + const certIDPromises = []; //endregion + //region Create all "certIDs" for input certificates + + var _iteratorNormalCompletion = true; + var _didIteratorError = false; + var _iteratorError = undefined; + + try { + for (var _iterator = this.tbsResponseData.responses[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { + const response = _step.value; + const hashAlgorithm = (0, _common.getAlgorithmByOID)(response.certID.hashAlgorithm.algorithmId); + if ("name" in hashAlgorithm === false) return Promise.reject(`Wrong CertID hashing algorithm: ${response.certID.hashAlgorithm.algorithmId}`); + + if (hashAlgorithm.name in hashesObject === false) { + hashesObject[hashAlgorithm.name] = 1; + const certID = new _CertID.default(); + certIDs.push(certID); + certIDPromises.push(certID.createForCertificate(certificate, { + hashAlgorithm: hashAlgorithm.name, + issuerCertificate + })); + } + } + } catch (err) { + _didIteratorError = true; + _iteratorError = err; + } finally { + try { + if (!_iteratorNormalCompletion && _iterator.return != null) { + _iterator.return(); + } + } finally { + if (_didIteratorError) { + throw _iteratorError; + } + } + } + + sequence = sequence.then(() => Promise.all(certIDPromises)); //endregion + //region Compare all response's "certIDs" with identifiers for input certificate + + sequence = sequence.then(() => { + var _iteratorNormalCompletion2 = true; + var _didIteratorError2 = false; + var _iteratorError2 = undefined; + + try { + for (var _iterator2 = this.tbsResponseData.responses[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { + const response = _step2.value; + + for (var _i = 0, _certIDs = certIDs; _i < _certIDs.length; _i++) { + const id = _certIDs[_i]; + + if (response.certID.isEqual(id)) { + result.isForCertificate = true; + + try { + switch (response.certStatus.idBlock.isConstructed) { + case true: + if (response.certStatus.idBlock.tagNumber === 1) result.status = 1; // revoked + + break; + + case false: + switch (response.certStatus.idBlock.tagNumber) { + case 0: + // good + result.status = 0; + break; + + case 2: + // unknown + result.status = 2; + break; + + default: + } + + break; + + default: + } + } catch (ex) {} + + return result; + } + } + } + } catch (err) { + _didIteratorError2 = true; + _iteratorError2 = err; + } finally { + try { + if (!_iteratorNormalCompletion2 && _iterator2.return != null) { + _iterator2.return(); + } + } finally { + if (_didIteratorError2) { + throw _iteratorError2; + } + } + } + + return result; + }); //endregion + + return sequence; + } //********************************************************************************** + + /** + * Make signature for current OCSP Basic Response + * @param {Object} privateKey Private key for "subjectPublicKeyInfo" structure + * @param {string} [hashAlgorithm="SHA-1"] Hashing algorithm. Default SHA-1 + * @returns {Promise} + */ + + + sign(privateKey, hashAlgorithm = "SHA-1") { + //region Initial checking + //region Get a private key from function parameter + if (typeof privateKey === "undefined") return Promise.reject("Need to provide a private key for signing"); //endregion + //endregion + //region Initial variables + + let sequence = Promise.resolve(); + let parameters; + const engine = (0, _common.getEngine)(); //endregion + //region Get a "default parameters" for current algorithm and set correct signature algorithm + + sequence = sequence.then(() => engine.subtle.getSignatureParameters(privateKey, hashAlgorithm)); + sequence = sequence.then(result => { + parameters = result.parameters; + this.signatureAlgorithm = result.signatureAlgorithm; + }); //endregion + //region Create TBS data for signing + + sequence = sequence.then(() => { + this.tbsResponseData.tbs = this.tbsResponseData.toSchema(true).toBER(false); + }); //endregion + //region Signing TBS data on provided private key + + sequence = sequence.then(() => engine.subtle.signWithPrivateKey(this.tbsResponseData.tbs, privateKey, parameters)); + sequence = sequence.then(result => { + this.signature = new asn1js.BitString({ + valueHex: result + }); + }); //endregion + + return sequence; + } //********************************************************************************** + + /** + * Verify existing OCSP Basic Response + * @param {Object} parameters Additional parameters + * @returns {Promise} + */ + + + verify(parameters = {}) { + //region Initial variables + let signerCert = null; + let certIndex = -1; + let sequence = Promise.resolve(); + let trustedCerts = []; + + const _this = this; + + const engine = (0, _common.getEngine)(); //endregion + //region Check amount of certificates + + if ("certs" in this === false) return Promise.reject("No certificates attached to the BasicOCSPResponce"); //endregion + //region Get input values + + if ("trustedCerts" in parameters) trustedCerts = parameters.trustedCerts; //endregion + //region Aux functions + + /** + * Check CA flag for the certificate + * @param {Certificate} cert Certificate to find CA flag for + * @returns {*} + */ + + function checkCA(cert) { + //region Do not include signer's certificate + if (cert.issuer.isEqual(signerCert.issuer) === true && cert.serialNumber.isEqual(signerCert.serialNumber) === true) return null; //endregion + + let isCA = false; + var _iteratorNormalCompletion3 = true; + var _didIteratorError3 = false; + var _iteratorError3 = undefined; + + try { + for (var _iterator3 = cert.extensions[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) { + const extension = _step3.value; + + if (extension.extnID === "2.5.29.19") // BasicConstraints + { + if ("cA" in extension.parsedValue) { + if (extension.parsedValue.cA === true) isCA = true; + } + } + } + } catch (err) { + _didIteratorError3 = true; + _iteratorError3 = err; + } finally { + try { + if (!_iteratorNormalCompletion3 && _iterator3.return != null) { + _iterator3.return(); + } + } finally { + if (_didIteratorError3) { + throw _iteratorError3; + } + } + } + + if (isCA) return cert; + return null; + } //endregion + //region Get a "crypto" extension + + + const crypto = (0, _common.getCrypto)(); + if (typeof crypto === "undefined") return Promise.reject("Unable to create WebCrypto object"); //endregion + //region Find correct value for "responderID" + + switch (true) { + case this.tbsResponseData.responderID instanceof _RelativeDistinguishedNames.default: + // [1] Name + sequence = sequence.then(() => { + var _iteratorNormalCompletion4 = true; + var _didIteratorError4 = false; + var _iteratorError4 = undefined; + + try { + for (var _iterator4 = _this.certs.entries()[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) { + const _step4$value = _slicedToArray(_step4.value, 2), + index = _step4$value[0], + certificate = _step4$value[1]; + + if (certificate.subject.isEqual(_this.tbsResponseData.responderID)) { + certIndex = index; + break; + } + } + } catch (err) { + _didIteratorError4 = true; + _iteratorError4 = err; + } finally { + try { + if (!_iteratorNormalCompletion4 && _iterator4.return != null) { + _iterator4.return(); + } + } finally { + if (_didIteratorError4) { + throw _iteratorError4; + } + } + } + }); + break; + + case this.tbsResponseData.responderID instanceof asn1js.OctetString: + // [2] KeyHash + sequence = sequence.then(() => Promise.all(Array.from(_this.certs, element => crypto.digest({ + name: "sha-1" + }, new Uint8Array(element.subjectPublicKeyInfo.subjectPublicKey.valueBlock.valueHex)))).then(results => { + var _iteratorNormalCompletion5 = true; + var _didIteratorError5 = false; + var _iteratorError5 = undefined; + + try { + for (var _iterator5 = _this.certs.entries()[Symbol.iterator](), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) { + const _step5$value = _slicedToArray(_step5.value, 1), + index = _step5$value[0]; + + if ((0, _pvutils.isEqualBuffer)(results[index], _this.tbsResponseData.responderID.valueBlock.valueHex)) { + certIndex = index; + break; + } + } + } catch (err) { + _didIteratorError5 = true; + _iteratorError5 = err; + } finally { + try { + if (!_iteratorNormalCompletion5 && _iterator5.return != null) { + _iterator5.return(); + } + } finally { + if (_didIteratorError5) { + throw _iteratorError5; + } + } + } + })); + break; + + default: + return Promise.reject("Wrong value for responderID"); + } //endregion + //region Make additional verification for signer's certificate + + + sequence = sequence.then(() => { + if (certIndex === -1) return Promise.reject("Correct certificate was not found in OCSP response"); + signerCert = this.certs[certIndex]; + return Promise.all(Array.from(_this.certs, element => checkCA(element))).then(promiseResults => { + const additionalCerts = []; + additionalCerts.push(signerCert); + var _iteratorNormalCompletion6 = true; + var _didIteratorError6 = false; + var _iteratorError6 = undefined; + + try { + for (var _iterator6 = promiseResults[Symbol.iterator](), _step6; !(_iteratorNormalCompletion6 = (_step6 = _iterator6.next()).done); _iteratorNormalCompletion6 = true) { + const promiseResult = _step6.value; + if (promiseResult !== null) additionalCerts.push(promiseResult); + } + } catch (err) { + _didIteratorError6 = true; + _iteratorError6 = err; + } finally { + try { + if (!_iteratorNormalCompletion6 && _iterator6.return != null) { + _iterator6.return(); + } + } finally { + if (_didIteratorError6) { + throw _iteratorError6; + } + } + } + + const certChain = new _CertificateChainValidationEngine.default({ + certs: additionalCerts, + trustedCerts + }); + return certChain.verify().then(verificationResult => { + if (verificationResult.result === true) return Promise.resolve(); + return Promise.reject("Validation of signer's certificate failed"); + }, error => Promise.reject(`Validation of signer's certificate failed with error: ${error instanceof Object ? error.resultMessage : error}`)); + }, promiseError => Promise.reject(`Error during checking certificates for CA flag: ${promiseError}`)); + }); //endregion + + sequence = sequence.then(() => engine.subtle.verifyWithPublicKey(this.tbsResponseData.tbs, this.signature, this.certs[certIndex].subjectPublicKeyInfo, this.signatureAlgorithm)); + return sequence; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = BasicOCSPResponse; + +},{"./AlgorithmIdentifier.js":4,"./CertID.js":18,"./Certificate.js":19,"./CertificateChainValidationEngine.js":20,"./RelativeDistinguishedNames.js":89,"./ResponseData.js":92,"./common.js":110,"asn1js":112,"pvutils":113}],14:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from https://docs.microsoft.com/en-us/windows/desktop/seccrypto/certification-authority-renewal + */ +class CAVersion { + //********************************************************************************** + + /** + * Constructor for CAVersion class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {number} + * @desc certificateIndex + */ + this.certificateIndex = (0, _pvutils.getParametersValue)(parameters, "certificateIndex", CAVersion.defaultValues("certificateIndex")); + /** + * @type {number} + * @desc keyIndex + */ + + this.keyIndex = (0, _pvutils.getParametersValue)(parameters, "keyIndex", CAVersion.defaultValues("keyIndex")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "certificateIndex": + case "keyIndex": + return 0; + + default: + throw new Error(`Invalid member name for CAVersion class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * CAVersion ::= INTEGER + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + return new asn1js.Integer(); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Check the schema is valid + if (schema.constructor.blockName() !== asn1js.Integer.blockName()) throw new Error("Object's schema was not verified against input data for CAVersion"); //endregion + //region Check length of the input value and correct it if needed + + let value = schema.valueBlock.valueHex.slice(0); + const valueView = new Uint8Array(value); + + switch (true) { + case value.byteLength < 4: + { + const tempValue = new ArrayBuffer(4); + const tempValueView = new Uint8Array(tempValue); + tempValueView.set(valueView, 4 - value.byteLength); + value = tempValue.slice(0); + } + break; + + case value.byteLength > 4: + { + const tempValue = new ArrayBuffer(4); + const tempValueView = new Uint8Array(tempValue); + tempValueView.set(valueView.slice(0, 4)); + value = tempValue.slice(0); + } + break; + + default: + } //endregion + //region Get internal properties from parsed schema + + + const keyIndexBuffer = value.slice(0, 2); + const keyIndexView8 = new Uint8Array(keyIndexBuffer); + let temp = keyIndexView8[0]; + keyIndexView8[0] = keyIndexView8[1]; + keyIndexView8[1] = temp; + const keyIndexView16 = new Uint16Array(keyIndexBuffer); + this.keyIndex = keyIndexView16[0]; + const certificateIndexBuffer = value.slice(2); + const certificateIndexView8 = new Uint8Array(certificateIndexBuffer); + temp = certificateIndexView8[0]; + certificateIndexView8[0] = certificateIndexView8[1]; + certificateIndexView8[1] = temp; + const certificateIndexView16 = new Uint16Array(certificateIndexBuffer); + this.certificateIndex = certificateIndexView16[0]; //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Create raw values + const certificateIndexBuffer = new ArrayBuffer(2); + const certificateIndexView = new Uint16Array(certificateIndexBuffer); + certificateIndexView[0] = this.certificateIndex; + const certificateIndexView8 = new Uint8Array(certificateIndexBuffer); + let temp = certificateIndexView8[0]; + certificateIndexView8[0] = certificateIndexView8[1]; + certificateIndexView8[1] = temp; + const keyIndexBuffer = new ArrayBuffer(2); + const keyIndexView = new Uint16Array(keyIndexBuffer); + keyIndexView[0] = this.keyIndex; + const keyIndexView8 = new Uint8Array(keyIndexBuffer); + temp = keyIndexView8[0]; + keyIndexView8[0] = keyIndexView8[1]; + keyIndexView8[1] = temp; //endregion + //region Construct and return new ASN.1 schema for this object + + return new asn1js.Integer({ + valueHex: (0, _pvutils.utilConcatBuf)(keyIndexBuffer, certificateIndexBuffer) + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + return { + certificateIndex: this.certificateIndex, + keyIndex: this.keyIndex + }; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = CAVersion; + +},{"asn1js":112,"pvutils":113}],15:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _CertificateRevocationList = _interopRequireDefault(require("./CertificateRevocationList.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC7292 + */ +class CRLBag { + //********************************************************************************** + + /** + * Constructor for CRLBag class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {string} + * @desc crlId + */ + this.crlId = (0, _pvutils.getParametersValue)(parameters, "crlId", CRLBag.defaultValues("crlId")); + /** + * @type {*} + * @desc crlValue + */ + + this.crlValue = (0, _pvutils.getParametersValue)(parameters, "crlValue", CRLBag.defaultValues("crlValue")); + if ("parsedValue" in parameters) + /** + * @type {*} + * @desc parsedValue + */ + this.parsedValue = (0, _pvutils.getParametersValue)(parameters, "parsedValue", CRLBag.defaultValues("parsedValue")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "crlId": + return ""; + + case "crlValue": + return new asn1js.Any(); + + case "parsedValue": + return {}; + + default: + throw new Error(`Invalid member name for CRLBag class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + + + static compareWithDefault(memberName, memberValue) { + switch (memberName) { + case "crlId": + return memberValue === ""; + + case "crlValue": + return memberValue instanceof asn1js.Any; + + case "parsedValue": + return memberValue instanceof Object && Object.keys(memberValue).length === 0; + + default: + throw new Error(`Invalid member name for CRLBag class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * CRLBag ::= SEQUENCE { + * crlId BAG-TYPE.&id ({CRLTypes}), + * crlValue [0] EXPLICIT BAG-TYPE.&Type ({CRLTypes}{@crlId}) + *} + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [id] + * @property {string} [value] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [new asn1js.ObjectIdentifier({ + name: names.id || "id" + }), new asn1js.Constructed({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: [new asn1js.Any({ + name: names.value || "value" + })] // EXPLICIT ANY value + + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["crlId", "crlValue"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, CRLBag.schema({ + names: { + id: "crlId", + value: "crlValue" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for CRLBag"); //endregion + //region Get internal properties from parsed schema + + this.crlId = asn1.result.crlId.valueBlock.toString(); + this.crlValue = asn1.result.crlValue; + + switch (this.crlId) { + case "1.2.840.113549.1.9.23.1": + // x509CRL + { + const asn1Inner = asn1js.fromBER(this.certValue.valueBlock.valueHex); + this.parsedValue = new _CertificateRevocationList.default({ + schema: asn1Inner.result + }); + } + break; + + default: + throw new Error(`Incorrect "crlId" value in CRLBag: ${this.crlId}`); + } //endregion + + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Construct and return new ASN.1 schema for this object + if ("parsedValue" in this) { + this.certId = "1.2.840.113549.1.9.23.1"; + this.certValue = new asn1js.OctetString({ + valueHex: this.parsedValue.toSchema().toBER(false) + }); + } + + return new asn1js.Sequence({ + value: [new asn1js.ObjectIdentifier({ + value: this.crlId + }), new asn1js.Constructed({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: [this.crlValue.toSchema()] + })] + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + return { + crlId: this.crlId, + crlValue: this.crlValue.toJSON() + }; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = CRLBag; + +},{"./CertificateRevocationList.js":22,"asn1js":112,"pvutils":113}],16:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _DistributionPoint = _interopRequireDefault(require("./DistributionPoint.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC5280 + */ +class CRLDistributionPoints { + //********************************************************************************** + + /** + * Constructor for CRLDistributionPoints class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {Array.} + * @desc distributionPoints + */ + this.distributionPoints = (0, _pvutils.getParametersValue)(parameters, "distributionPoints", CRLDistributionPoints.defaultValues("distributionPoints")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "distributionPoints": + return []; + + default: + throw new Error(`Invalid member name for CRLDistributionPoints class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * CRLDistributionPoints ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [distributionPoints] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [new asn1js.Repeated({ + name: names.distributionPoints || "", + value: _DistributionPoint.default.schema() + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["distributionPoints"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, CRLDistributionPoints.schema({ + names: { + distributionPoints: "distributionPoints" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for CRLDistributionPoints"); //endregion + //region Get internal properties from parsed schema + + this.distributionPoints = Array.from(asn1.result.distributionPoints, element => new _DistributionPoint.default({ + schema: element + })); //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Construct and return new ASN.1 schema for this object + return new asn1js.Sequence({ + value: Array.from(this.distributionPoints, element => element.toSchema()) + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + return { + distributionPoints: Array.from(this.distributionPoints, element => element.toJSON()) + }; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = CRLDistributionPoints; + +},{"./DistributionPoint.js":29,"asn1js":112,"pvutils":113}],17:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _Certificate = _interopRequireDefault(require("./Certificate.js")); + +var _AttributeCertificateV = _interopRequireDefault(require("./AttributeCertificateV2.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC7292 + */ +class CertBag { + //********************************************************************************** + + /** + * Constructor for CertBag class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {string} + * @desc certId + */ + this.certId = (0, _pvutils.getParametersValue)(parameters, "certId", CertBag.defaultValues("certId")); + /** + * @type {*} + * @desc certValue + */ + + this.certValue = (0, _pvutils.getParametersValue)(parameters, "certValue", CertBag.defaultValues("certValue")); + if ("parsedValue" in parameters) + /** + * @type {*} + * @desc parsedValue + */ + this.parsedValue = (0, _pvutils.getParametersValue)(parameters, "parsedValue", CertBag.defaultValues("parsedValue")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "certId": + return ""; + + case "certValue": + return new asn1js.Any(); + + case "parsedValue": + return {}; + + default: + throw new Error(`Invalid member name for CertBag class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + + + static compareWithDefault(memberName, memberValue) { + switch (memberName) { + case "certId": + return memberValue === ""; + + case "certValue": + return memberValue instanceof asn1js.Any; + + case "parsedValue": + return memberValue instanceof Object && Object.keys(memberValue).length === 0; + + default: + throw new Error(`Invalid member name for CertBag class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * CertBag ::= SEQUENCE { + * certId BAG-TYPE.&id ({CertTypes}), + * certValue [0] EXPLICIT BAG-TYPE.&Type ({CertTypes}{@certId}) + * } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [id] + * @property {string} [value] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [new asn1js.ObjectIdentifier({ + name: names.id || "id" + }), new asn1js.Constructed({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: [new asn1js.Any({ + name: names.value || "value" + })] // EXPLICIT ANY value + + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["certId", "certValue"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, CertBag.schema({ + names: { + id: "certId", + value: "certValue" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for CertBag"); //endregion + //region Get internal properties from parsed schema + + this.certId = asn1.result.certId.valueBlock.toString(); + this.certValue = asn1.result.certValue; + + switch (this.certId) { + case "1.2.840.113549.1.9.22.1": + // x509Certificate + { + const asn1Inner = asn1js.fromBER(this.certValue.valueBlock.valueHex); + + try { + this.parsedValue = new _Certificate.default({ + schema: asn1Inner.result + }); + } catch (ex) // In some realizations the same OID used for attribute certificates + { + this.parsedValue = new _AttributeCertificateV.default({ + schema: asn1Inner.result + }); + } + } + break; + + case "1.2.840.113549.1.9.22.3": + // attributeCertificate - (!!!) THIS OID IS SUBJECT FOR CHANGE IN FUTURE (!!!) + { + const asn1Inner = asn1js.fromBER(this.certValue.valueBlock.valueHex); + this.parsedValue = new _AttributeCertificateV.default({ + schema: asn1Inner.result + }); + } + break; + + case "1.2.840.113549.1.9.22.2": // sdsiCertificate + + default: + throw new Error(`Incorrect "certId" value in CertBag: ${this.certId}`); + } //endregion + + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Construct and return new ASN.1 schema for this object + if ("parsedValue" in this) { + if ("acinfo" in this.parsedValue) // attributeCertificate + this.certId = "1.2.840.113549.1.9.22.3";else // x509Certificate + this.certId = "1.2.840.113549.1.9.22.1"; + this.certValue = new asn1js.OctetString({ + valueHex: this.parsedValue.toSchema().toBER(false) + }); + } + + return new asn1js.Sequence({ + value: [new asn1js.ObjectIdentifier({ + value: this.certId + }), new asn1js.Constructed({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: ["toSchema" in this.certValue ? this.certValue.toSchema() : this.certValue] + })] + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + return { + certId: this.certId, + certValue: this.certValue.toJSON() + }; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = CertBag; + +},{"./AttributeCertificateV2.js":8,"./Certificate.js":19,"asn1js":112,"pvutils":113}],18:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _common = require("./common.js"); + +var _AlgorithmIdentifier = _interopRequireDefault(require("./AlgorithmIdentifier.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC6960 + */ +class CertID { + //********************************************************************************** + + /** + * Constructor for CertID class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {AlgorithmIdentifier} + * @desc hashAlgorithm + */ + this.hashAlgorithm = (0, _pvutils.getParametersValue)(parameters, "hashAlgorithm", CertID.defaultValues("hashAlgorithm")); + /** + * @type {OctetString} + * @desc issuerNameHash + */ + + this.issuerNameHash = (0, _pvutils.getParametersValue)(parameters, "issuerNameHash", CertID.defaultValues("issuerNameHash")); + /** + * @type {OctetString} + * @desc issuerKeyHash + */ + + this.issuerKeyHash = (0, _pvutils.getParametersValue)(parameters, "issuerKeyHash", CertID.defaultValues("issuerKeyHash")); + /** + * @type {Integer} + * @desc serialNumber + */ + + this.serialNumber = (0, _pvutils.getParametersValue)(parameters, "serialNumber", CertID.defaultValues("serialNumber")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "hashAlgorithm": + return new _AlgorithmIdentifier.default(); + + case "issuerNameHash": + case "issuerKeyHash": + return new asn1js.OctetString(); + + case "serialNumber": + return new asn1js.Integer(); + + default: + throw new Error(`Invalid member name for CertID class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + + + static compareWithDefault(memberName, memberValue) { + switch (memberName) { + case "hashAlgorithm": + return memberValue.algorithmId === "" && "algorithmParams" in memberValue === false; + + case "issuerNameHash": + case "issuerKeyHash": + case "serialNumber": + return memberValue.isEqual(CertID.defaultValues(memberName)); + + default: + throw new Error(`Invalid member name for CertID class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * CertID ::= SEQUENCE { + * hashAlgorithm AlgorithmIdentifier, + * issuerNameHash OCTET STRING, -- Hash of issuer's DN + * issuerKeyHash OCTET STRING, -- Hash of issuer's public key + * serialNumber CertificateSerialNumber } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [hashAlgorithm] + * @property {string} [hashAlgorithmObject] + * @property {string} [issuerNameHash] + * @property {string} [issuerKeyHash] + * @property {string} [serialNumber] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [_AlgorithmIdentifier.default.schema(names.hashAlgorithmObject || { + names: { + blockName: names.hashAlgorithm || "" + } + }), new asn1js.OctetString({ + name: names.issuerNameHash || "" + }), new asn1js.OctetString({ + name: names.issuerKeyHash || "" + }), new asn1js.Integer({ + name: names.serialNumber || "" + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["hashAlgorithm", "issuerNameHash", "issuerKeyHash", "serialNumber"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, CertID.schema({ + names: { + hashAlgorithm: "hashAlgorithm", + issuerNameHash: "issuerNameHash", + issuerKeyHash: "issuerKeyHash", + serialNumber: "serialNumber" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for CertID"); //endregion + //region Get internal properties from parsed schema + + this.hashAlgorithm = new _AlgorithmIdentifier.default({ + schema: asn1.result.hashAlgorithm + }); + this.issuerNameHash = asn1.result.issuerNameHash; + this.issuerKeyHash = asn1.result.issuerKeyHash; + this.serialNumber = asn1.result.serialNumber; //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Construct and return new ASN.1 schema for this object + return new asn1js.Sequence({ + value: [this.hashAlgorithm.toSchema(), this.issuerNameHash, this.issuerKeyHash, this.serialNumber] + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + return { + hashAlgorithm: this.hashAlgorithm.toJSON(), + issuerNameHash: this.issuerNameHash.toJSON(), + issuerKeyHash: this.issuerKeyHash.toJSON(), + serialNumber: this.serialNumber.toJSON() + }; + } //********************************************************************************** + + /** + * Check that two "CertIDs" are equal + * @param {CertID} certificateID Identifier of the certificate to be checked + * @returns {boolean} + */ + + + isEqual(certificateID) { + //region Check "hashAlgorithm" + if (!this.hashAlgorithm.algorithmId === certificateID.hashAlgorithm.algorithmId) return false; //endregion + //region Check "issuerNameHash" + + if ((0, _pvutils.isEqualBuffer)(this.issuerNameHash.valueBlock.valueHex, certificateID.issuerNameHash.valueBlock.valueHex) === false) return false; //endregion + //region Check "issuerKeyHash" + + if ((0, _pvutils.isEqualBuffer)(this.issuerKeyHash.valueBlock.valueHex, certificateID.issuerKeyHash.valueBlock.valueHex) === false) return false; //endregion + //region Check "serialNumber" + + if (!this.serialNumber.isEqual(certificateID.serialNumber)) return false; //endregion + + return true; + } //********************************************************************************** + + /** + * Making OCSP certificate identifier for specific certificate + * @param {Certificate} certificate Certificate making OCSP Request for + * @param {Object} parameters Additional parameters + * @returns {Promise} + */ + + + createForCertificate(certificate, parameters) { + //region Initial variables + let sequence = Promise.resolve(); + let issuerCertificate; //endregion + //region Get a "crypto" extension + + const crypto = (0, _common.getCrypto)(); + if (typeof crypto === "undefined") return Promise.reject("Unable to create WebCrypto object"); //endregion + //region Check input parameters + + if ("hashAlgorithm" in parameters === false) return Promise.reject("Parameter \"hashAlgorithm\" is mandatory for \"OCSP_REQUEST.createForCertificate\""); + const hashOID = (0, _common.getOIDByAlgorithm)({ + name: parameters.hashAlgorithm + }); + if (hashOID === "") return Promise.reject(`Incorrect "hashAlgorithm": ${this.hashAlgorithm}`); + this.hashAlgorithm = new _AlgorithmIdentifier.default({ + algorithmId: hashOID, + algorithmParams: new asn1js.Null() + }); + if ("issuerCertificate" in parameters) issuerCertificate = parameters.issuerCertificate;else return Promise.reject("Parameter \"issuerCertificate\" is mandatory for \"OCSP_REQUEST.createForCertificate\""); //endregion + //region Initialize "serialNumber" field + + this.serialNumber = certificate.serialNumber; //endregion + //region Create "issuerNameHash" + + sequence = sequence.then(() => crypto.digest({ + name: parameters.hashAlgorithm + }, issuerCertificate.subject.toSchema().toBER(false)), error => Promise.reject(error)); //endregion + //region Create "issuerKeyHash" + + sequence = sequence.then(result => { + this.issuerNameHash = new asn1js.OctetString({ + valueHex: result + }); + const issuerKeyBuffer = issuerCertificate.subjectPublicKeyInfo.subjectPublicKey.valueBlock.valueHex; + return crypto.digest({ + name: parameters.hashAlgorithm + }, issuerKeyBuffer); + }, error => Promise.reject(error)).then(result => { + this.issuerKeyHash = new asn1js.OctetString({ + valueHex: result + }); + }, error => Promise.reject(error)); //endregion + + return sequence; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = CertID; + +},{"./AlgorithmIdentifier.js":4,"./common.js":110,"asn1js":112,"pvutils":113}],19:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _common = require("./common.js"); + +var _AlgorithmIdentifier = _interopRequireDefault(require("./AlgorithmIdentifier.js")); + +var _RelativeDistinguishedNames = _interopRequireDefault(require("./RelativeDistinguishedNames.js")); + +var _Time = _interopRequireDefault(require("./Time.js")); + +var _PublicKeyInfo = _interopRequireDefault(require("./PublicKeyInfo.js")); + +var _Extension = _interopRequireDefault(require("./Extension.js")); + +var _Extensions = _interopRequireDefault(require("./Extensions.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** +function tbsCertificate(parameters = {}) { + //TBSCertificate ::= SEQUENCE { + // version [0] EXPLICIT Version DEFAULT v1, + // serialNumber CertificateSerialNumber, + // signature AlgorithmIdentifier, + // issuer Name, + // validity Validity, + // subject Name, + // subjectPublicKeyInfo SubjectPublicKeyInfo, + // issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, + // -- If present, version MUST be v2 or v3 + // subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL, + // -- If present, version MUST be v2 or v3 + // extensions [3] EXPLICIT Extensions OPTIONAL + // -- If present, version MUST be v3 + //} + + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [tbsCertificateVersion] + * @property {string} [tbsCertificateSerialNumber] + * @property {string} [signature] + * @property {string} [issuer] + * @property {string} [tbsCertificateValidity] + * @property {string} [notBefore] + * @property {string} [notAfter] + * @property {string} [subject] + * @property {string} [subjectPublicKeyInfo] + * @property {string} [tbsCertificateIssuerUniqueID] + * @property {string} [tbsCertificateSubjectUniqueID] + * @property {string} [extensions] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "tbsCertificate", + value: [new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: [new asn1js.Integer({ + name: names.tbsCertificateVersion || "tbsCertificate.version" + }) // EXPLICIT integer value + ] + }), new asn1js.Integer({ + name: names.tbsCertificateSerialNumber || "tbsCertificate.serialNumber" + }), _AlgorithmIdentifier.default.schema(names.signature || { + names: { + blockName: "tbsCertificate.signature" + } + }), _RelativeDistinguishedNames.default.schema(names.issuer || { + names: { + blockName: "tbsCertificate.issuer" + } + }), new asn1js.Sequence({ + name: names.tbsCertificateValidity || "tbsCertificate.validity", + value: [_Time.default.schema(names.notBefore || { + names: { + utcTimeName: "tbsCertificate.notBefore", + generalTimeName: "tbsCertificate.notBefore" + } + }), _Time.default.schema(names.notAfter || { + names: { + utcTimeName: "tbsCertificate.notAfter", + generalTimeName: "tbsCertificate.notAfter" + } + })] + }), _RelativeDistinguishedNames.default.schema(names.subject || { + names: { + blockName: "tbsCertificate.subject" + } + }), _PublicKeyInfo.default.schema(names.subjectPublicKeyInfo || { + names: { + blockName: "tbsCertificate.subjectPublicKeyInfo" + } + }), new asn1js.Primitive({ + name: names.tbsCertificateIssuerUniqueID || "tbsCertificate.issuerUniqueID", + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + + } + }), // IMPLICIT bistring value + new asn1js.Primitive({ + name: names.tbsCertificateSubjectUniqueID || "tbsCertificate.subjectUniqueID", + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 2 // [2] + + } + }), // IMPLICIT bistring value + new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 3 // [3] + + }, + value: [_Extensions.default.schema(names.extensions || { + names: { + blockName: "tbsCertificate.extensions" + } + })] + }) // EXPLICIT SEQUENCE value + ] + }); +} //************************************************************************************** + +/** + * Class from RFC5280 + */ + + +class Certificate { + //********************************************************************************** + + /** + * Constructor for Certificate class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {ArrayBuffer} + * @desc ToBeSigned (TBS) part of the certificate + */ + this.tbs = (0, _pvutils.getParametersValue)(parameters, "tbs", Certificate.defaultValues("tbs")); + /** + * @type {number} + * @desc Version number + */ + + this.version = (0, _pvutils.getParametersValue)(parameters, "version", Certificate.defaultValues("version")); + /** + * @type {Integer} + * @desc Serial number of the certificate + */ + + this.serialNumber = (0, _pvutils.getParametersValue)(parameters, "serialNumber", Certificate.defaultValues("serialNumber")); + /** + * @type {AlgorithmIdentifier} + * @desc This field contains the algorithm identifier for the algorithm used by the CA to sign the certificate + */ + + this.signature = (0, _pvutils.getParametersValue)(parameters, "signature", Certificate.defaultValues("signature")); + /** + * @type {RelativeDistinguishedNames} + * @desc The issuer field identifies the entity that has signed and issued the certificate + */ + + this.issuer = (0, _pvutils.getParametersValue)(parameters, "issuer", Certificate.defaultValues("issuer")); + /** + * @type {Time} + * @desc The date on which the certificate validity period begins + */ + + this.notBefore = (0, _pvutils.getParametersValue)(parameters, "notBefore", Certificate.defaultValues("notBefore")); + /** + * @type {Time} + * @desc The date on which the certificate validity period ends + */ + + this.notAfter = (0, _pvutils.getParametersValue)(parameters, "notAfter", Certificate.defaultValues("notAfter")); + /** + * @type {RelativeDistinguishedNames} + * @desc The subject field identifies the entity associated with the public key stored in the subject public key field + */ + + this.subject = (0, _pvutils.getParametersValue)(parameters, "subject", Certificate.defaultValues("subject")); + /** + * @type {PublicKeyInfo} + * @desc This field is used to carry the public key and identify the algorithm with which the key is used + */ + + this.subjectPublicKeyInfo = (0, _pvutils.getParametersValue)(parameters, "subjectPublicKeyInfo", Certificate.defaultValues("subjectPublicKeyInfo")); + if ("issuerUniqueID" in parameters) + /** + * @type {ArrayBuffer} + * @desc The subject and issuer unique identifiers are present in the certificate to handle the possibility of reuse of subject and/or issuer names over time + */ + this.issuerUniqueID = (0, _pvutils.getParametersValue)(parameters, "issuerUniqueID", Certificate.defaultValues("issuerUniqueID")); + if ("subjectUniqueID" in parameters) + /** + * @type {ArrayBuffer} + * @desc The subject and issuer unique identifiers are present in the certificate to handle the possibility of reuse of subject and/or issuer names over time + */ + this.subjectUniqueID = (0, _pvutils.getParametersValue)(parameters, "subjectUniqueID", Certificate.defaultValues("subjectUniqueID")); + if ("extensions" in parameters) + /** + * @type {Array} + * @desc If present, this field is a SEQUENCE of one or more certificate extensions + */ + this.extensions = (0, _pvutils.getParametersValue)(parameters, "extensions", Certificate.defaultValues("extensions")); + /** + * @type {AlgorithmIdentifier} + * @desc The signatureAlgorithm field contains the identifier for the cryptographic algorithm used by the CA to sign this certificate + */ + + this.signatureAlgorithm = (0, _pvutils.getParametersValue)(parameters, "signatureAlgorithm", Certificate.defaultValues("signatureAlgorithm")); + /** + * @type {BitString} + * @desc The signatureValue field contains a digital signature computed upon the ASN.1 DER encoded tbsCertificate + */ + + this.signatureValue = (0, _pvutils.getParametersValue)(parameters, "signatureValue", Certificate.defaultValues("signatureValue")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "tbs": + return new ArrayBuffer(0); + + case "version": + return 0; + + case "serialNumber": + return new asn1js.Integer(); + + case "signature": + return new _AlgorithmIdentifier.default(); + + case "issuer": + return new _RelativeDistinguishedNames.default(); + + case "notBefore": + return new _Time.default(); + + case "notAfter": + return new _Time.default(); + + case "subject": + return new _RelativeDistinguishedNames.default(); + + case "subjectPublicKeyInfo": + return new _PublicKeyInfo.default(); + + case "issuerUniqueID": + return new ArrayBuffer(0); + + case "subjectUniqueID": + return new ArrayBuffer(0); + + case "extensions": + return []; + + case "signatureAlgorithm": + return new _AlgorithmIdentifier.default(); + + case "signatureValue": + return new asn1js.BitString(); + + default: + throw new Error(`Invalid member name for Certificate class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * Certificate ::= SEQUENCE { + * tbsCertificate TBSCertificate, + * signatureAlgorithm AlgorithmIdentifier, + * signatureValue BIT STRING } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [tbsCertificate] + * @property {string} [signatureAlgorithm] + * @property {string} [signatureValue] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [tbsCertificate(names.tbsCertificate), _AlgorithmIdentifier.default.schema(names.signatureAlgorithm || { + names: { + blockName: "signatureAlgorithm" + } + }), new asn1js.BitString({ + name: names.signatureValue || "signatureValue" + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["tbsCertificate", "tbsCertificate.extensions", "tbsCertificate.version", "tbsCertificate.serialNumber", "tbsCertificate.signature", "tbsCertificate.issuer", "tbsCertificate.notBefore", "tbsCertificate.notAfter", "tbsCertificate.subject", "tbsCertificate.subjectPublicKeyInfo", "tbsCertificate.issuerUniqueID", "tbsCertificate.subjectUniqueID", "signatureAlgorithm", "signatureValue"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, Certificate.schema({ + names: { + tbsCertificate: { + names: { + extensions: { + names: { + extensions: "tbsCertificate.extensions" + } + } + } + } + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for Certificate"); //endregion + //region Get internal properties from parsed schema + + this.tbs = asn1.result.tbsCertificate.valueBeforeDecode; + if ("tbsCertificate.version" in asn1.result) this.version = asn1.result["tbsCertificate.version"].valueBlock.valueDec; + this.serialNumber = asn1.result["tbsCertificate.serialNumber"]; + this.signature = new _AlgorithmIdentifier.default({ + schema: asn1.result["tbsCertificate.signature"] + }); + this.issuer = new _RelativeDistinguishedNames.default({ + schema: asn1.result["tbsCertificate.issuer"] + }); + this.notBefore = new _Time.default({ + schema: asn1.result["tbsCertificate.notBefore"] + }); + this.notAfter = new _Time.default({ + schema: asn1.result["tbsCertificate.notAfter"] + }); + this.subject = new _RelativeDistinguishedNames.default({ + schema: asn1.result["tbsCertificate.subject"] + }); + this.subjectPublicKeyInfo = new _PublicKeyInfo.default({ + schema: asn1.result["tbsCertificate.subjectPublicKeyInfo"] + }); + if ("tbsCertificate.issuerUniqueID" in asn1.result) this.issuerUniqueID = asn1.result["tbsCertificate.issuerUniqueID"].valueBlock.valueHex; + if ("tbsCertificate.subjectUniqueID" in asn1.result) this.subjectUniqueID = asn1.result["tbsCertificate.subjectUniqueID"].valueBlock.valueHex; + if ("tbsCertificate.extensions" in asn1.result) this.extensions = Array.from(asn1.result["tbsCertificate.extensions"], element => new _Extension.default({ + schema: element + })); + this.signatureAlgorithm = new _AlgorithmIdentifier.default({ + schema: asn1.result.signatureAlgorithm + }); + this.signatureValue = asn1.result.signatureValue; //endregion + } //********************************************************************************** + + /** + * Create ASN.1 schema for existing values of TBS part for the certificate + */ + + + encodeTBS() { + //region Create array for output sequence + const outputArray = []; + + if ("version" in this && this.version !== Certificate.defaultValues("version")) { + outputArray.push(new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: [new asn1js.Integer({ + value: this.version + }) // EXPLICIT integer value + ] + })); + } + + outputArray.push(this.serialNumber); + outputArray.push(this.signature.toSchema()); + outputArray.push(this.issuer.toSchema()); + outputArray.push(new asn1js.Sequence({ + value: [this.notBefore.toSchema(), this.notAfter.toSchema()] + })); + outputArray.push(this.subject.toSchema()); + outputArray.push(this.subjectPublicKeyInfo.toSchema()); + + if ("issuerUniqueID" in this) { + outputArray.push(new asn1js.Primitive({ + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + + }, + valueHex: this.issuerUniqueID + })); + } + + if ("subjectUniqueID" in this) { + outputArray.push(new asn1js.Primitive({ + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 2 // [2] + + }, + valueHex: this.subjectUniqueID + })); + } + + if ("extensions" in this) { + outputArray.push(new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 3 // [3] + + }, + value: [new asn1js.Sequence({ + value: Array.from(this.extensions, element => element.toSchema()) + })] + })); + } //endregion + //region Create and return output sequence + + + return new asn1js.Sequence({ + value: outputArray + }); //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema(encodeFlag = false) { + let tbsSchema = {}; //region Decode stored TBS value + + if (encodeFlag === false) { + if (this.tbs.length === 0) // No stored certificate TBS part + return Certificate.schema().value[0]; + tbsSchema = asn1js.fromBER(this.tbs).result; + } //endregion + //region Create TBS schema via assembling from TBS parts + else tbsSchema = this.encodeTBS(); //endregion + //region Construct and return new ASN.1 schema for this object + + + return new asn1js.Sequence({ + value: [tbsSchema, this.signatureAlgorithm.toSchema(), this.signatureValue] + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + const object = { + tbs: (0, _pvutils.bufferToHexCodes)(this.tbs, 0, this.tbs.byteLength), + serialNumber: this.serialNumber.toJSON(), + signature: this.signature.toJSON(), + issuer: this.issuer.toJSON(), + notBefore: this.notBefore.toJSON(), + notAfter: this.notAfter.toJSON(), + subject: this.subject.toJSON(), + subjectPublicKeyInfo: this.subjectPublicKeyInfo.toJSON(), + signatureAlgorithm: this.signatureAlgorithm.toJSON(), + signatureValue: this.signatureValue.toJSON() + }; + if ("version" in this && this.version !== Certificate.defaultValues("version")) object.version = this.version; + if ("issuerUniqueID" in this) object.issuerUniqueID = (0, _pvutils.bufferToHexCodes)(this.issuerUniqueID, 0, this.issuerUniqueID.byteLength); + if ("subjectUniqueID" in this) object.subjectUniqueID = (0, _pvutils.bufferToHexCodes)(this.subjectUniqueID, 0, this.subjectUniqueID.byteLength); + if ("extensions" in this) object.extensions = Array.from(this.extensions, element => element.toJSON()); + return object; + } //********************************************************************************** + + /** + * Importing public key for current certificate + */ + + + getPublicKey(parameters = null) { + return (0, _common.getEngine)().subtle.getPublicKey(this.subjectPublicKeyInfo, this.signatureAlgorithm, parameters); + } //********************************************************************************** + + /** + * Get hash value for subject public key (default SHA-1) + * @param {String} [hashAlgorithm=SHA-1] Hashing algorithm name + */ + + + getKeyHash(hashAlgorithm = "SHA-1") { + //region Get a "crypto" extension + const crypto = (0, _common.getCrypto)(); + if (typeof crypto === "undefined") return Promise.reject("Unable to create WebCrypto object"); //endregion + + return crypto.digest({ + name: hashAlgorithm + }, new Uint8Array(this.subjectPublicKeyInfo.subjectPublicKey.valueBlock.valueHex)); + } //********************************************************************************** + + /** + * Make a signature for current value from TBS section + * @param {Object} privateKey Private key for "subjectPublicKeyInfo" structure + * @param {string} [hashAlgorithm="SHA-1"] Hashing algorithm + */ + + + sign(privateKey, hashAlgorithm = "SHA-1") { + //region Initial checking + //region Check private key + if (typeof privateKey === "undefined") return Promise.reject("Need to provide a private key for signing"); //endregion + //endregion + //region Initial variables + + let sequence = Promise.resolve(); + let parameters; + const engine = (0, _common.getEngine)(); //endregion + //region Get a "default parameters" for current algorithm and set correct signature algorithm + + sequence = sequence.then(() => engine.subtle.getSignatureParameters(privateKey, hashAlgorithm)); + sequence = sequence.then(result => { + parameters = result.parameters; + this.signature = result.signatureAlgorithm; + this.signatureAlgorithm = result.signatureAlgorithm; + }); //endregion + //region Create TBS data for signing + + sequence = sequence.then(() => { + this.tbs = this.encodeTBS().toBER(false); + }); //endregion + //region Signing TBS data on provided private key + + sequence = sequence.then(() => engine.subtle.signWithPrivateKey(this.tbs, privateKey, parameters)); + sequence = sequence.then(result => { + this.signatureValue = new asn1js.BitString({ + valueHex: result + }); + }); //endregion + + return sequence; + } //********************************************************************************** + + + verify(issuerCertificate = null) { + //region Global variables + let subjectPublicKeyInfo = {}; //endregion + //region Set correct "subjectPublicKeyInfo" value + + if (issuerCertificate !== null) subjectPublicKeyInfo = issuerCertificate.subjectPublicKeyInfo;else { + if (this.issuer.isEqual(this.subject)) // Self-signed certificate + subjectPublicKeyInfo = this.subjectPublicKeyInfo; + } + if (subjectPublicKeyInfo instanceof _PublicKeyInfo.default === false) return Promise.reject("Please provide issuer certificate as a parameter"); //endregion + + return (0, _common.getEngine)().subtle.verifyWithPublicKey(this.tbs, this.signatureValue, subjectPublicKeyInfo, this.signatureAlgorithm); + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = Certificate; + +},{"./AlgorithmIdentifier.js":4,"./Extension.js":38,"./Extensions.js":39,"./PublicKeyInfo.js":78,"./RelativeDistinguishedNames.js":89,"./Time.js":107,"./common.js":110,"asn1js":112,"pvutils":113}],20:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var _pvutils = require("pvutils"); + +var _common = require("./common.js"); + +function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } } + +function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; } + +//************************************************************************************** +class CertificateChainValidationEngine { + //********************************************************************************** + + /** + * Constructor for CertificateChainValidationEngine class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {Array.} + * @desc Array of pre-defined trusted (by user) certificates + */ + this.trustedCerts = (0, _pvutils.getParametersValue)(parameters, "trustedCerts", this.defaultValues("trustedCerts")); + /** + * @type {Array.} + * @desc Array with certificate chain. Could be only one end-user certificate in there! + */ + + this.certs = (0, _pvutils.getParametersValue)(parameters, "certs", this.defaultValues("certs")); + /** + * @type {Array.} + * @desc Array of all CRLs for all certificates from certificate chain + */ + + this.crls = (0, _pvutils.getParametersValue)(parameters, "crls", this.defaultValues("crls")); + /** + * @type {Array} + * @desc Array of all OCSP responses + */ + + this.ocsps = (0, _pvutils.getParametersValue)(parameters, "ocsps", this.defaultValues("ocsps")); + /** + * @type {Date} + * @desc The date at which the check would be + */ + + this.checkDate = (0, _pvutils.getParametersValue)(parameters, "checkDate", this.defaultValues("checkDate")); + /** + * @type {Function} + * @desc The date at which the check would be + */ + + this.findOrigin = (0, _pvutils.getParametersValue)(parameters, "findOrigin", this.defaultValues("findOrigin")); + /** + * @type {Function} + * @desc The date at which the check would be + */ + + this.findIssuer = (0, _pvutils.getParametersValue)(parameters, "findIssuer", this.defaultValues("findIssuer")); //endregion + } //********************************************************************************** + + + static defaultFindOrigin(certificate, validationEngine) { + //region Firstly encode TBS for certificate + if (certificate.tbs.byteLength === 0) certificate.tbs = certificate.encodeTBS(); //endregion + //region Search in Intermediate Certificates + + var _iteratorNormalCompletion = true; + var _didIteratorError = false; + var _iteratorError = undefined; + + try { + for (var _iterator = validationEngine.certs[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { + const localCert = _step.value; + //region Firstly encode TBS for certificate + if (localCert.tbs.byteLength === 0) localCert.tbs = localCert.encodeTBS(); //endregion + + if ((0, _pvutils.isEqualBuffer)(certificate.tbs, localCert.tbs)) return "Intermediate Certificates"; + } //endregion + //region Search in Trusted Certificates + + } catch (err) { + _didIteratorError = true; + _iteratorError = err; + } finally { + try { + if (!_iteratorNormalCompletion && _iterator.return != null) { + _iterator.return(); + } + } finally { + if (_didIteratorError) { + throw _iteratorError; + } + } + } + + var _iteratorNormalCompletion2 = true; + var _didIteratorError2 = false; + var _iteratorError2 = undefined; + + try { + for (var _iterator2 = validationEngine.trustedCerts[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { + const trustedCert = _step2.value; + //region Firstly encode TBS for certificate + if (trustedCert.tbs.byteLength === 0) trustedCert.tbs = trustedCert.encodeTBS(); //endregion + + if ((0, _pvutils.isEqualBuffer)(certificate.tbs, trustedCert.tbs)) return "Trusted Certificates"; + } //endregion + + } catch (err) { + _didIteratorError2 = true; + _iteratorError2 = err; + } finally { + try { + if (!_iteratorNormalCompletion2 && _iterator2.return != null) { + _iterator2.return(); + } + } finally { + if (_didIteratorError2) { + throw _iteratorError2; + } + } + } + + return "Unknown"; + } //********************************************************************************** + + + defaultFindIssuer(certificate, validationEngine) { + return _asyncToGenerator(function* () { + //region Initial variables + let result = []; + let keyIdentifier = null; + let authorityCertIssuer = null; + let authorityCertSerialNumber = null; //endregion + //region Speed-up searching in case of self-signed certificates + + if (certificate.subject.isEqual(certificate.issuer)) { + try { + const verificationResult = yield certificate.verify(); + if (verificationResult === true) return [certificate]; + } catch (ex) {} + } //endregion + //region Find values to speed-up search + + + if ("extensions" in certificate) { + var _iteratorNormalCompletion3 = true; + var _didIteratorError3 = false; + var _iteratorError3 = undefined; + + try { + for (var _iterator3 = certificate.extensions[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) { + const extension = _step3.value; + + if (extension.extnID === "2.5.29.35") // AuthorityKeyIdentifier + { + if ("keyIdentifier" in extension.parsedValue) keyIdentifier = extension.parsedValue.keyIdentifier;else { + if ("authorityCertIssuer" in extension.parsedValue) authorityCertIssuer = extension.parsedValue.authorityCertIssuer; + if ("authorityCertSerialNumber" in extension.parsedValue) authorityCertSerialNumber = extension.parsedValue.authorityCertSerialNumber; + } + break; + } + } + } catch (err) { + _didIteratorError3 = true; + _iteratorError3 = err; + } finally { + try { + if (!_iteratorNormalCompletion3 && _iterator3.return != null) { + _iterator3.return(); + } + } finally { + if (_didIteratorError3) { + throw _iteratorError3; + } + } + } + } //endregion + //region Aux function + + + function checkCertificate(possibleIssuer) { + //region Firstly search for appropriate extensions + if (keyIdentifier !== null) { + if ("extensions" in possibleIssuer) { + let extensionFound = false; + var _iteratorNormalCompletion4 = true; + var _didIteratorError4 = false; + var _iteratorError4 = undefined; + + try { + for (var _iterator4 = possibleIssuer.extensions[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) { + const extension = _step4.value; + + if (extension.extnID === "2.5.29.14") // SubjectKeyIdentifier + { + extensionFound = true; + if ((0, _pvutils.isEqualBuffer)(extension.parsedValue.valueBlock.valueHex, keyIdentifier.valueBlock.valueHex)) result.push(possibleIssuer); + break; + } + } + } catch (err) { + _didIteratorError4 = true; + _iteratorError4 = err; + } finally { + try { + if (!_iteratorNormalCompletion4 && _iterator4.return != null) { + _iterator4.return(); + } + } finally { + if (_didIteratorError4) { + throw _iteratorError4; + } + } + } + + if (extensionFound) return; + } + } //endregion + //region Now search for authorityCertSerialNumber + + + let authorityCertSerialNumberEqual = false; + if (authorityCertSerialNumber !== null) authorityCertSerialNumberEqual = possibleIssuer.serialNumber.isEqual(authorityCertSerialNumber); //endregion + //region And at least search for Issuer data + + if (authorityCertIssuer !== null) { + if (possibleIssuer.subject.isEqual(authorityCertIssuer)) { + if (authorityCertSerialNumberEqual) result.push(possibleIssuer); + } + } else { + if (certificate.issuer.isEqual(possibleIssuer.subject)) result.push(possibleIssuer); + } //endregion + + } //endregion + //region Search in Trusted Certificates + + + var _iteratorNormalCompletion5 = true; + var _didIteratorError5 = false; + var _iteratorError5 = undefined; + + try { + for (var _iterator5 = validationEngine.trustedCerts[Symbol.iterator](), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) { + const trustedCert = _step5.value; + checkCertificate(trustedCert); + } //endregion + //region Search in Intermediate Certificates + + } catch (err) { + _didIteratorError5 = true; + _iteratorError5 = err; + } finally { + try { + if (!_iteratorNormalCompletion5 && _iterator5.return != null) { + _iterator5.return(); + } + } finally { + if (_didIteratorError5) { + throw _iteratorError5; + } + } + } + + var _iteratorNormalCompletion6 = true; + var _didIteratorError6 = false; + var _iteratorError6 = undefined; + + try { + for (var _iterator6 = validationEngine.certs[Symbol.iterator](), _step6; !(_iteratorNormalCompletion6 = (_step6 = _iterator6.next()).done); _iteratorNormalCompletion6 = true) { + const intermediateCert = _step6.value; + checkCertificate(intermediateCert); + } //endregion + //region Now perform certificate verification checking + + } catch (err) { + _didIteratorError6 = true; + _iteratorError6 = err; + } finally { + try { + if (!_iteratorNormalCompletion6 && _iterator6.return != null) { + _iterator6.return(); + } + } finally { + if (_didIteratorError6) { + throw _iteratorError6; + } + } + } + + for (let i = 0; i < result.length; i++) { + try { + const verificationResult = yield certificate.verify(result[i]); + if (verificationResult === false) result.splice(i, 1); + } catch (ex) { + result.splice(i, 1); // Something wrong, remove the certificate + } + } //endregion + + + return result; + })(); + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + defaultValues(memberName) { + switch (memberName) { + case "trustedCerts": + return []; + + case "certs": + return []; + + case "crls": + return []; + + case "ocsps": + return []; + + case "checkDate": + return new Date(); + + case "findOrigin": + return CertificateChainValidationEngine.defaultFindOrigin; + + case "findIssuer": + return this.defaultFindIssuer; + + default: + throw new Error(`Invalid member name for CertificateChainValidationEngine class: ${memberName}`); + } + } //********************************************************************************** + + + sort(passedWhenNotRevValues = false) { + var _this2 = this; + + return _asyncToGenerator(function* () { + //region Initial variables + const localCerts = []; + const _this = _this2; //endregion + //region Building certificate path + + function buildPath(_x) { + return _buildPath.apply(this, arguments); + } //endregion + //region Find CRL for specific certificate + + + function _buildPath() { + _buildPath = _asyncToGenerator(function* (certificate) { + const result = []; //region Aux function checking array for unique elements + + function checkUnique(array) { + let unique = true; + + for (let i = 0; i < array.length; i++) { + for (let j = 0; j < array.length; j++) { + if (j === i) continue; + + if (array[i] === array[j]) { + unique = false; + break; + } + } + + if (!unique) break; + } + + return unique; + } //endregion + + + const findIssuerResult = yield _this.findIssuer(certificate, _this); + if (findIssuerResult.length === 0) throw new Error("No valid certificate paths found"); + + for (let i = 0; i < findIssuerResult.length; i++) { + if ((0, _pvutils.isEqualBuffer)(findIssuerResult[i].tbs, certificate.tbs)) { + result.push([findIssuerResult[i]]); + continue; + } + + const buildPathResult = yield buildPath(findIssuerResult[i]); + + for (let j = 0; j < buildPathResult.length; j++) { + const copy = buildPathResult[j].slice(); + copy.splice(0, 0, findIssuerResult[i]); + if (checkUnique(copy)) result.push(copy);else result.push(buildPathResult[j]); + } + } + + return result; + }); + return _buildPath.apply(this, arguments); + } + + function findCRL(_x2) { + return _findCRL.apply(this, arguments); + } //endregion + //region Find OCSP for specific certificate + + + function _findCRL() { + _findCRL = _asyncToGenerator(function* (certificate) { + //region Initial variables + const issuerCertificates = []; + const crls = []; + const crlsAndCertificates = []; //endregion + //region Find all possible CRL issuers + + issuerCertificates.push(...localCerts.filter(element => certificate.issuer.isEqual(element.subject))); + + if (issuerCertificates.length === 0) { + return { + status: 1, + statusMessage: "No certificate's issuers" + }; + } //endregion + //region Find all CRLs for certificate's issuer + + + crls.push(..._this.crls.filter(element => element.issuer.isEqual(certificate.issuer))); + + if (crls.length === 0) { + return { + status: 2, + statusMessage: "No CRLs for specific certificate issuer" + }; + } //endregion + //region Find specific certificate of issuer for each CRL + + + for (let i = 0; i < crls.length; i++) { + //region Check "nextUpdate" for the CRL + // The "nextUpdate" is older than "checkDate". + // Thus we should do have another, updated CRL. + // Thus the CRL assumed to be invalid. + if (crls[i].nextUpdate.value < _this.checkDate) continue; //endregion + + for (let j = 0; j < issuerCertificates.length; j++) { + try { + const result = yield crls[i].verify({ + issuerCertificate: issuerCertificates[j] + }); + + if (result) { + crlsAndCertificates.push({ + crl: crls[i], + certificate: issuerCertificates[j] + }); + break; + } + } catch (ex) {} + } + } //endregion + + + if (crlsAndCertificates.length) { + return { + status: 0, + statusMessage: "", + result: crlsAndCertificates + }; + } + + return { + status: 3, + statusMessage: "No valid CRLs found" + }; + }); + return _findCRL.apply(this, arguments); + } + + function findOCSP(_x3, _x4) { + return _findOCSP.apply(this, arguments); + } //endregion + //region Check for certificate to be CA + + + function _findOCSP() { + _findOCSP = _asyncToGenerator(function* (certificate, issuerCertificate) { + //region Get hash algorithm from certificate + const hashAlgorithm = (0, _common.getAlgorithmByOID)(certificate.signatureAlgorithm.algorithmId); + if ("name" in hashAlgorithm === false) return 1; + if ("hash" in hashAlgorithm === false) return 1; //endregion + //region Search for OCSP response for the certificate + + for (let i = 0; i < _this.ocsps.length; i++) { + const result = yield _this.ocsps[i].getCertificateStatus(certificate, issuerCertificate); + + if (result.isForCertificate) { + if (result.status === 0) return 0; + return 1; + } + } //endregion + + + return 2; + }); + return _findOCSP.apply(this, arguments); + } + + function checkForCA(_x5) { + return _checkForCA.apply(this, arguments); + } //endregion + //region Basic check for certificate path + + + function _checkForCA() { + _checkForCA = _asyncToGenerator(function* (certificate, needToCheckCRL = false) { + //region Initial variables + let isCA = false; + let mustBeCA = false; + let keyUsagePresent = false; + let cRLSign = false; //endregion + + if ("extensions" in certificate) { + for (let j = 0; j < certificate.extensions.length; j++) { + if (certificate.extensions[j].critical === true && "parsedValue" in certificate.extensions[j] === false) { + return { + result: false, + resultCode: 6, + resultMessage: `Unable to parse critical certificate extension: ${certificate.extensions[j].extnID}` + }; + } + + if (certificate.extensions[j].extnID === "2.5.29.15") // KeyUsage + { + keyUsagePresent = true; + const view = new Uint8Array(certificate.extensions[j].parsedValue.valueBlock.valueHex); + if ((view[0] & 0x04) === 0x04) // Set flag "keyCertSign" + mustBeCA = true; + if ((view[0] & 0x02) === 0x02) // Set flag "cRLSign" + cRLSign = true; + } + + if (certificate.extensions[j].extnID === "2.5.29.19") // BasicConstraints + { + if ("cA" in certificate.extensions[j].parsedValue) { + if (certificate.extensions[j].parsedValue.cA === true) isCA = true; + } + } + } + + if (mustBeCA === true && isCA === false) { + return { + result: false, + resultCode: 3, + resultMessage: "Unable to build certificate chain - using \"keyCertSign\" flag set without BasicConstaints" + }; + } + + if (keyUsagePresent === true && isCA === true && mustBeCA === false) { + return { + result: false, + resultCode: 4, + resultMessage: "Unable to build certificate chain - \"keyCertSign\" flag was not set" + }; + } // noinspection OverlyComplexBooleanExpressionJS + + + if (isCA === true && keyUsagePresent === true && needToCheckCRL && cRLSign === false) { + return { + result: false, + resultCode: 5, + resultMessage: "Unable to build certificate chain - intermediate certificate must have \"cRLSign\" key usage flag" + }; + } + } + + if (isCA === false) { + return { + result: false, + resultCode: 7, + resultMessage: "Unable to build certificate chain - more than one possible end-user certificate" + }; + } + + return { + result: true, + resultCode: 0, + resultMessage: "" + }; + }); + return _checkForCA.apply(this, arguments); + } + + function basicCheck(_x6, _x7) { + return _basicCheck.apply(this, arguments); + } //endregion + //region Do main work + //region Initialize "localCerts" by value of "_this.certs" + "_this.trustedCerts" arrays + + + function _basicCheck() { + _basicCheck = _asyncToGenerator(function* (path, checkDate) { + //region Check that all dates are valid + for (let i = 0; i < path.length; i++) { + if (path[i].notBefore.value > checkDate || path[i].notAfter.value < checkDate) { + return { + result: false, + resultCode: 8, + resultMessage: "The certificate is either not yet valid or expired" + }; + } + } //endregion + //region Check certificate name chain + // We should have at least two certificates: end entity and trusted root + + + if (path.length < 2) { + return { + result: false, + resultCode: 9, + resultMessage: "Too short certificate path" + }; + } + + for (let i = path.length - 2; i >= 0; i--) { + //region Check that we do not have a "self-signed" certificate + if (path[i].issuer.isEqual(path[i].subject) === false) { + if (path[i].issuer.isEqual(path[i + 1].subject) === false) { + return { + result: false, + resultCode: 10, + resultMessage: "Incorrect name chaining" + }; + } + } //endregion + + } //endregion + //region Check each certificate (except "trusted root") to be non-revoked + + + if (_this.crls.length !== 0 || _this.ocsps.length !== 0) // If CRLs and OCSPs are empty then we consider all certificates to be valid + { + for (let i = 0; i < path.length - 1; i++) { + //region Initial variables + let ocspResult = 2; + let crlResult = { + status: 0, + statusMessage: "" + }; //endregion + //region Check OCSPs first + + if (_this.ocsps.length !== 0) { + ocspResult = yield findOCSP(path[i], path[i + 1]); + + switch (ocspResult) { + case 0: + continue; + + case 1: + return { + result: false, + resultCode: 12, + resultMessage: "One of certificates was revoked via OCSP response" + }; + + case 2: + // continue to check the certificate with CRL + break; + + default: + } + } //endregion + //region Check CRLs + + + if (_this.crls.length !== 0) { + crlResult = yield findCRL(path[i]); + + if (crlResult.status === 0) { + for (let j = 0; j < crlResult.result.length; j++) { + //region Check that the CRL issuer certificate have not been revoked + const isCertificateRevoked = crlResult.result[j].crl.isCertificateRevoked(path[i]); + + if (isCertificateRevoked) { + return { + result: false, + resultCode: 12, + resultMessage: "One of certificates had been revoked" + }; + } //endregion + //region Check that the CRL issuer certificate is a CA certificate + + + const isCertificateCA = yield checkForCA(crlResult.result[j].certificate, true); + + if (isCertificateCA.result === false) { + return { + result: false, + resultCode: 13, + resultMessage: "CRL issuer certificate is not a CA certificate or does not have crlSign flag" + }; + } //endregion + + } + } else { + if (passedWhenNotRevValues === false) { + throw { + result: false, + resultCode: 11, + resultMessage: `No revocation values found for one of certificates: ${crlResult.statusMessage}` + }; + } + } + } else { + if (ocspResult === 2) { + return { + result: false, + resultCode: 11, + resultMessage: "No revocation values found for one of certificates" + }; + } + } //endregion + //region Check we do have links to revocation values inside issuer's certificate + + + if (ocspResult === 2 && crlResult.status === 2 && passedWhenNotRevValues) { + const issuerCertificate = path[i + 1]; + let extensionFound = false; + + if ("extensions" in issuerCertificate) { + var _iteratorNormalCompletion7 = true; + var _didIteratorError7 = false; + var _iteratorError7 = undefined; + + try { + for (var _iterator7 = issuerCertificate.extensions[Symbol.iterator](), _step7; !(_iteratorNormalCompletion7 = (_step7 = _iterator7.next()).done); _iteratorNormalCompletion7 = true) { + const extension = _step7.value; + + switch (extension.extnID) { + case "2.5.29.31": // CRLDistributionPoints + + case "2.5.29.46": // FreshestCRL + + case "1.3.6.1.5.5.7.1.1": + // AuthorityInfoAccess + extensionFound = true; + break; + + default: + } + } + } catch (err) { + _didIteratorError7 = true; + _iteratorError7 = err; + } finally { + try { + if (!_iteratorNormalCompletion7 && _iterator7.return != null) { + _iterator7.return(); + } + } finally { + if (_didIteratorError7) { + throw _iteratorError7; + } + } + } + } + + if (extensionFound) { + throw { + result: false, + resultCode: 11, + resultMessage: `No revocation values found for one of certificates: ${crlResult.statusMessage}` + }; + } + } //endregion + + } + } //endregion + //region Check each certificate (except "end entity") in the path to be a CA certificate + + + for (let i = 1; i < path.length; i++) { + const result = yield checkForCA(path[i]); + + if (result.result === false) { + return { + result: false, + resultCode: 14, + resultMessage: "One of intermediate certificates is not a CA certificate" + }; + } + } //endregion + + + return { + result: true + }; + }); + return _basicCheck.apply(this, arguments); + } + + localCerts.push(..._this.trustedCerts); + localCerts.push(..._this.certs); //endregion + //region Check all certificates for been unique + + for (let i = 0; i < localCerts.length; i++) { + for (let j = 0; j < localCerts.length; j++) { + if (i === j) continue; + + if ((0, _pvutils.isEqualBuffer)(localCerts[i].tbs, localCerts[j].tbs)) { + localCerts.splice(j, 1); + i = 0; + break; + } + } + } //endregion + //region Initial variables + + + let result; + const certificatePath = [localCerts[localCerts.length - 1]]; // The "end entity" certificate must be the least in "certs" array + //endregion + //region Build path for "end entity" certificate + + result = yield buildPath(localCerts[localCerts.length - 1]); + + if (result.length === 0) { + return { + result: false, + resultCode: 60, + resultMessage: "Unable to find certificate path" + }; + } //endregion + //region Exclude certificate paths not ended with "trusted roots" + + + for (let i = 0; i < result.length; i++) { + let found = false; + + for (let j = 0; j < result[i].length; j++) { + const certificate = result[i][j]; + + for (let k = 0; k < _this.trustedCerts.length; k++) { + if ((0, _pvutils.isEqualBuffer)(certificate.tbs, _this.trustedCerts[k].tbs)) { + found = true; + break; + } + } + + if (found) break; + } + + if (!found) { + result.splice(i, 1); + i = 0; + } + } + + if (result.length === 0) { + throw { + result: false, + resultCode: 97, + resultMessage: "No valid certificate paths found" + }; + } //endregion + //region Find shortest certificate path (for the moment it is the only criteria) + + + let shortestLength = result[0].length; + let shortestIndex = 0; + + for (let i = 0; i < result.length; i++) { + if (result[i].length < shortestLength) { + shortestLength = result[i].length; + shortestIndex = i; + } + } //endregion + //region Create certificate path for basic check + + + for (let i = 0; i < result[shortestIndex].length; i++) certificatePath.push(result[shortestIndex][i]); //endregion + //region Perform basic checking for all certificates in the path + + + result = yield basicCheck(certificatePath, _this.checkDate); + if (result.result === false) throw result; //endregion + + return certificatePath; //endregion + })(); + } //********************************************************************************** + + /** + * Major verification function for certificate chain. + * @param {{initialPolicySet, initialExplicitPolicy, initialPolicyMappingInhibit, initialInhibitPolicy, initialPermittedSubtreesSet, initialExcludedSubtreesSet, initialRequiredNameForms}} [parameters] + * @returns {Promise} + */ + + + verify(parameters = {}) { + var _this3 = this; + + return _asyncToGenerator(function* () { + //region Auxiliary functions for name constraints checking + function compareDNSName(name, constraint) { + /// Compare two dNSName values + /// DNS from name + /// Constraint for DNS from name + /// Boolean result - valid or invalid the "name" against the "constraint" + //region Make a "string preparation" for both name and constrain + const namePrepared = (0, _common.stringPrep)(name); + const constraintPrepared = (0, _common.stringPrep)(constraint); //endregion + //region Make a "splitted" versions of "constraint" and "name" + + const nameSplitted = namePrepared.split("."); + const constraintSplitted = constraintPrepared.split("."); //endregion + //region Length calculation and additional check + + const nameLen = nameSplitted.length; + const constrLen = constraintSplitted.length; + if (nameLen === 0 || constrLen === 0 || nameLen < constrLen) return false; //endregion + //region Check that no part of "name" has zero length + + for (let i = 0; i < nameLen; i++) { + if (nameSplitted[i].length === 0) return false; + } //endregion + //region Check that no part of "constraint" has zero length + + + for (let i = 0; i < constrLen; i++) { + if (constraintSplitted[i].length === 0) { + if (i === 0) { + if (constrLen === 1) return false; + continue; + } + + return false; + } + } //endregion + //region Check that "name" has a tail as "constraint" + + + for (let i = 0; i < constrLen; i++) { + if (constraintSplitted[constrLen - 1 - i].length === 0) continue; + if (nameSplitted[nameLen - 1 - i].localeCompare(constraintSplitted[constrLen - 1 - i]) !== 0) return false; + } //endregion + + + return true; + } + + function compareRFC822Name(name, constraint) { + /// Compare two rfc822Name values + /// E-mail address from name + /// Constraint for e-mail address from name + /// Boolean result - valid or invalid the "name" against the "constraint" + //region Make a "string preparation" for both name and constrain + const namePrepared = (0, _common.stringPrep)(name); + const constraintPrepared = (0, _common.stringPrep)(constraint); //endregion + //region Make a "splitted" versions of "constraint" and "name" + + const nameSplitted = namePrepared.split("@"); + const constraintSplitted = constraintPrepared.split("@"); //endregion + //region Splitted array length checking + + if (nameSplitted.length === 0 || constraintSplitted.length === 0 || nameSplitted.length < constraintSplitted.length) return false; //endregion + + if (constraintSplitted.length === 1) { + const result = compareDNSName(nameSplitted[1], constraintSplitted[0]); + + if (result) { + //region Make a "splitted" versions of domain name from "constraint" and "name" + const ns = nameSplitted[1].split("."); + const cs = constraintSplitted[0].split("."); //endregion + + if (cs[0].length === 0) return true; + return ns.length === cs.length; + } + + return false; + } + + return namePrepared.localeCompare(constraintPrepared) === 0; + } + + function compareUniformResourceIdentifier(name, constraint) { + /// Compare two uniformResourceIdentifier values + /// uniformResourceIdentifier from name + /// Constraint for uniformResourceIdentifier from name + /// Boolean result - valid or invalid the "name" against the "constraint" + //region Make a "string preparation" for both name and constrain + let namePrepared = (0, _common.stringPrep)(name); + const constraintPrepared = (0, _common.stringPrep)(constraint); //endregion + //region Find out a major URI part to compare with + + const ns = namePrepared.split("/"); + const cs = constraintPrepared.split("/"); + if (cs.length > 1) // Malformed constraint + return false; + + if (ns.length > 1) // Full URI string + { + for (let i = 0; i < ns.length; i++) { + if (ns[i].length > 0 && ns[i].charAt(ns[i].length - 1) !== ":") { + const nsPort = ns[i].split(":"); + namePrepared = nsPort[0]; + break; + } + } + } //endregion + + + const result = compareDNSName(namePrepared, constraintPrepared); + + if (result) { + //region Make a "splitted" versions of "constraint" and "name" + const nameSplitted = namePrepared.split("."); + const constraintSplitted = constraintPrepared.split("."); //endregion + + if (constraintSplitted[0].length === 0) return true; + return nameSplitted.length === constraintSplitted.length; + } + + return false; + } + + function compareIPAddress(name, constraint) { + /// Compare two iPAddress values + /// iPAddress from name + /// Constraint for iPAddress from name + /// Boolean result - valid or invalid the "name" against the "constraint" + //region Common variables + const nameView = new Uint8Array(name.valueBlock.valueHex); + const constraintView = new Uint8Array(constraint.valueBlock.valueHex); //endregion + //region Work with IPv4 addresses + + if (nameView.length === 4 && constraintView.length === 8) { + for (let i = 0; i < 4; i++) { + if ((nameView[i] ^ constraintView[i]) & constraintView[i + 4]) return false; + } + + return true; + } //endregion + //region Work with IPv6 addresses + + + if (nameView.length === 16 && constraintView.length === 32) { + for (let i = 0; i < 16; i++) { + if ((nameView[i] ^ constraintView[i]) & constraintView[i + 16]) return false; + } + + return true; + } //endregion + + + return false; + } + + function compareDirectoryName(name, constraint) { + /// Compare two directoryName values + /// directoryName from name + /// Constraint for directoryName from name + /// Boolean flag - should be comparision interrupted after first match or we need to match all "constraints" parts + /// Boolean result - valid or invalid the "name" against the "constraint" + //region Initial check + if (name.typesAndValues.length === 0 || constraint.typesAndValues.length === 0) return true; + if (name.typesAndValues.length < constraint.typesAndValues.length) return false; //endregion + //region Initial variables + + let result = true; + let nameStart = 0; //endregion + + for (let i = 0; i < constraint.typesAndValues.length; i++) { + let localResult = false; + + for (let j = nameStart; j < name.typesAndValues.length; j++) { + localResult = name.typesAndValues[j].isEqual(constraint.typesAndValues[i]); + if (name.typesAndValues[j].type === constraint.typesAndValues[i].type) result = result && localResult; + + if (localResult === true) { + if (nameStart === 0 || nameStart === j) { + nameStart = j + 1; + break; + } else // Structure of "name" must be the same with "constraint" + return false; + } + } + + if (localResult === false) return false; + } + + return nameStart === 0 ? false : result; + } //endregion + + + try { + //region Initial checks + if (_this3.certs.length === 0) throw "Empty certificate array"; //endregion + //region Get input variables + + let passedWhenNotRevValues = false; + if ("passedWhenNotRevValues" in parameters) passedWhenNotRevValues = parameters.passedWhenNotRevValues; + let initialPolicySet = []; + initialPolicySet.push("2.5.29.32.0"); // "anyPolicy" + + let initialExplicitPolicy = false; + let initialPolicyMappingInhibit = false; + let initialInhibitPolicy = false; + let initialPermittedSubtreesSet = []; // Array of "simpl.x509.GeneralSubtree" + + let initialExcludedSubtreesSet = []; // Array of "simpl.x509.GeneralSubtree" + + let initialRequiredNameForms = []; // Array of "simpl.x509.GeneralSubtree" + + if ("initialPolicySet" in parameters) initialPolicySet = parameters.initialPolicySet; + if ("initialExplicitPolicy" in parameters) initialExplicitPolicy = parameters.initialExplicitPolicy; + if ("initialPolicyMappingInhibit" in parameters) initialPolicyMappingInhibit = parameters.initialPolicyMappingInhibit; + if ("initialInhibitPolicy" in parameters) initialInhibitPolicy = parameters.initialInhibitPolicy; + if ("initialPermittedSubtreesSet" in parameters) initialPermittedSubtreesSet = parameters.initialPermittedSubtreesSet; + if ("initialExcludedSubtreesSet" in parameters) initialExcludedSubtreesSet = parameters.initialExcludedSubtreesSet; + if ("initialRequiredNameForms" in parameters) initialRequiredNameForms = parameters.initialRequiredNameForms; + let explicitPolicyIndicator = initialExplicitPolicy; + let policyMappingInhibitIndicator = initialPolicyMappingInhibit; + let inhibitAnyPolicyIndicator = initialInhibitPolicy; + const pendingConstraints = new Array(3); + pendingConstraints[0] = false; // For "explicitPolicyPending" + + pendingConstraints[1] = false; // For "policyMappingInhibitPending" + + pendingConstraints[2] = false; // For "inhibitAnyPolicyPending" + + let explicitPolicyPending = 0; + let policyMappingInhibitPending = 0; + let inhibitAnyPolicyPending = 0; + let permittedSubtrees = initialPermittedSubtreesSet; + let excludedSubtrees = initialExcludedSubtreesSet; + const requiredNameForms = initialRequiredNameForms; + let pathDepth = 1; //endregion + //region Sorting certificates in the chain array + + _this3.certs = yield _this3.sort(passedWhenNotRevValues); //endregion + //region Work with policies + //region Support variables + + const allPolicies = []; // Array of all policies (string values) + + allPolicies.push("2.5.29.32.0"); // Put "anyPolicy" at first place + + const policiesAndCerts = []; // In fact "array of array" where rows are for each specific policy, column for each certificate and value is "true/false" + + const anyPolicyArray = new Array(_this3.certs.length - 1); // Minus "trusted anchor" + + for (let ii = 0; ii < _this3.certs.length - 1; ii++) anyPolicyArray[ii] = true; + + policiesAndCerts.push(anyPolicyArray); + const policyMappings = new Array(_this3.certs.length - 1); // Array of "PolicyMappings" for each certificate + + const certPolicies = new Array(_this3.certs.length - 1); // Array of "CertificatePolicies" for each certificate + + let explicitPolicyStart = explicitPolicyIndicator ? _this3.certs.length - 1 : -1; //endregion + //region Gather all neccessary information from certificate chain + + for (let i = _this3.certs.length - 2; i >= 0; i--, pathDepth++) { + if ("extensions" in _this3.certs[i]) { + //region Get information about certificate extensions + for (let j = 0; j < _this3.certs[i].extensions.length; j++) { + //region CertificatePolicies + if (_this3.certs[i].extensions[j].extnID === "2.5.29.32") { + certPolicies[i] = _this3.certs[i].extensions[j].parsedValue; //region Remove entry from "anyPolicies" for the certificate + + for (let s = 0; s < allPolicies.length; s++) { + if (allPolicies[s] === "2.5.29.32.0") { + delete policiesAndCerts[s][i]; + break; + } + } //endregion + + + for (let k = 0; k < _this3.certs[i].extensions[j].parsedValue.certificatePolicies.length; k++) { + let policyIndex = -1; //region Try to find extension in "allPolicies" array + + for (let s = 0; s < allPolicies.length; s++) { + if (_this3.certs[i].extensions[j].parsedValue.certificatePolicies[k].policyIdentifier === allPolicies[s]) { + policyIndex = s; + break; + } + } //endregion + + + if (policyIndex === -1) { + allPolicies.push(_this3.certs[i].extensions[j].parsedValue.certificatePolicies[k].policyIdentifier); + const certArray = new Array(_this3.certs.length - 1); + certArray[i] = true; + policiesAndCerts.push(certArray); + } else policiesAndCerts[policyIndex][i] = true; + } + } //endregion + //region PolicyMappings + + + if (_this3.certs[i].extensions[j].extnID === "2.5.29.33") { + if (policyMappingInhibitIndicator) { + return { + result: false, + resultCode: 98, + resultMessage: "Policy mapping prohibited" + }; + } + + policyMappings[i] = _this3.certs[i].extensions[j].parsedValue; + } //endregion + //region PolicyConstraints + + + if (_this3.certs[i].extensions[j].extnID === "2.5.29.36") { + if (explicitPolicyIndicator === false) { + //region requireExplicitPolicy + if (_this3.certs[i].extensions[j].parsedValue.requireExplicitPolicy === 0) { + explicitPolicyIndicator = true; + explicitPolicyStart = i; + } else { + if (pendingConstraints[0] === false) { + pendingConstraints[0] = true; + explicitPolicyPending = _this3.certs[i].extensions[j].parsedValue.requireExplicitPolicy; + } else explicitPolicyPending = explicitPolicyPending > _this3.certs[i].extensions[j].parsedValue.requireExplicitPolicy ? _this3.certs[i].extensions[j].parsedValue.requireExplicitPolicy : explicitPolicyPending; + } //endregion + //region inhibitPolicyMapping + + + if (_this3.certs[i].extensions[j].parsedValue.inhibitPolicyMapping === 0) policyMappingInhibitIndicator = true;else { + if (pendingConstraints[1] === false) { + pendingConstraints[1] = true; + policyMappingInhibitPending = _this3.certs[i].extensions[j].parsedValue.inhibitPolicyMapping + 1; + } else policyMappingInhibitPending = policyMappingInhibitPending > _this3.certs[i].extensions[j].parsedValue.inhibitPolicyMapping + 1 ? _this3.certs[i].extensions[j].parsedValue.inhibitPolicyMapping + 1 : policyMappingInhibitPending; + } //endregion + } + } //endregion + //region InhibitAnyPolicy + + + if (_this3.certs[i].extensions[j].extnID === "2.5.29.54") { + if (inhibitAnyPolicyIndicator === false) { + if (_this3.certs[i].extensions[j].parsedValue.valueBlock.valueDec === 0) inhibitAnyPolicyIndicator = true;else { + if (pendingConstraints[2] === false) { + pendingConstraints[2] = true; + inhibitAnyPolicyPending = _this3.certs[i].extensions[j].parsedValue.valueBlock.valueDec; + } else inhibitAnyPolicyPending = inhibitAnyPolicyPending > _this3.certs[i].extensions[j].parsedValue.valueBlock.valueDec ? _this3.certs[i].extensions[j].parsedValue.valueBlock.valueDec : inhibitAnyPolicyPending; + } + } + } //endregion + + } //endregion + //region Check "inhibitAnyPolicyIndicator" + + + if (inhibitAnyPolicyIndicator === true) { + let policyIndex = -1; //region Find "anyPolicy" index + + for (let searchAnyPolicy = 0; searchAnyPolicy < allPolicies.length; searchAnyPolicy++) { + if (allPolicies[searchAnyPolicy] === "2.5.29.32.0") { + policyIndex = searchAnyPolicy; + break; + } + } //endregion + + + if (policyIndex !== -1) delete policiesAndCerts[0][i]; // Unset value to "undefined" for "anyPolicies" value for current certificate + } //endregion + //region Process with "pending constraints" + + + if (explicitPolicyIndicator === false) { + if (pendingConstraints[0] === true) { + explicitPolicyPending--; + + if (explicitPolicyPending === 0) { + explicitPolicyIndicator = true; + explicitPolicyStart = i; + pendingConstraints[0] = false; + } + } + } + + if (policyMappingInhibitIndicator === false) { + if (pendingConstraints[1] === true) { + policyMappingInhibitPending--; + + if (policyMappingInhibitPending === 0) { + policyMappingInhibitIndicator = true; + pendingConstraints[1] = false; + } + } + } + + if (inhibitAnyPolicyIndicator === false) { + if (pendingConstraints[2] === true) { + inhibitAnyPolicyPending--; + + if (inhibitAnyPolicyPending === 0) { + inhibitAnyPolicyIndicator = true; + pendingConstraints[2] = false; + } + } + } //endregion + + } + } //endregion + //region Working with policy mappings + + + for (let i = 0; i < _this3.certs.length - 1; i++) { + //region Check that there is "policy mapping" for level "i + 1" + if (i < _this3.certs.length - 2 && typeof policyMappings[i + 1] !== "undefined") { + for (let k = 0; k < policyMappings[i + 1].mappings.length; k++) { + //region Check that we do not have "anyPolicy" in current mapping + if (policyMappings[i + 1].mappings[k].issuerDomainPolicy === "2.5.29.32.0" || policyMappings[i + 1].mappings[k].subjectDomainPolicy === "2.5.29.32.0") { + return { + result: false, + resultCode: 99, + resultMessage: "The \"anyPolicy\" should not be a part of policy mapping scheme" + }; + } //endregion + //region Initial variables + + + let issuerDomainPolicyIndex = -1; + let subjectDomainPolicyIndex = -1; //endregion + //region Search for index of policies indedes + + for (let n = 0; n < allPolicies.length; n++) { + if (allPolicies[n] === policyMappings[i + 1].mappings[k].issuerDomainPolicy) issuerDomainPolicyIndex = n; + if (allPolicies[n] === policyMappings[i + 1].mappings[k].subjectDomainPolicy) subjectDomainPolicyIndex = n; + } //endregion + //region Delete existing "issuerDomainPolicy" because on the level we mapped the policy to another one + + + if (typeof policiesAndCerts[issuerDomainPolicyIndex][i] !== "undefined") delete policiesAndCerts[issuerDomainPolicyIndex][i]; //endregion + //region Check all policies for the certificate + + for (let j = 0; j < certPolicies[i].certificatePolicies.length; j++) { + if (policyMappings[i + 1].mappings[k].subjectDomainPolicy === certPolicies[i].certificatePolicies[j].policyIdentifier) { + //region Set mapped policy for current certificate + if (issuerDomainPolicyIndex !== -1 && subjectDomainPolicyIndex !== -1) { + for (let m = 0; m <= i; m++) { + if (typeof policiesAndCerts[subjectDomainPolicyIndex][m] !== "undefined") { + policiesAndCerts[issuerDomainPolicyIndex][m] = true; + delete policiesAndCerts[subjectDomainPolicyIndex][m]; + } + } + } //endregion + + } + } //endregion + + } + } //endregion + + } //endregion + //region Working with "explicitPolicyIndicator" and "anyPolicy" + + + for (let i = 0; i < allPolicies.length; i++) { + if (allPolicies[i] === "2.5.29.32.0") { + for (let j = 0; j < explicitPolicyStart; j++) delete policiesAndCerts[i][j]; + } + } //endregion + //region Create "set of authorities-constrained policies" + + + const authConstrPolicies = []; + + for (let i = 0; i < policiesAndCerts.length; i++) { + let found = true; + + for (let j = 0; j < _this3.certs.length - 1; j++) { + let anyPolicyFound = false; + + if (j < explicitPolicyStart && allPolicies[i] === "2.5.29.32.0" && allPolicies.length > 1) { + found = false; + break; + } + + if (typeof policiesAndCerts[i][j] === "undefined") { + if (j >= explicitPolicyStart) { + //region Search for "anyPolicy" in the policy set + for (let k = 0; k < allPolicies.length; k++) { + if (allPolicies[k] === "2.5.29.32.0") { + if (policiesAndCerts[k][j] === true) anyPolicyFound = true; + break; + } + } //endregion + + } + + if (!anyPolicyFound) { + found = false; + break; + } + } + } + + if (found === true) authConstrPolicies.push(allPolicies[i]); + } //endregion + //region Create "set of user-constrained policies" + + + let userConstrPolicies = []; + if (initialPolicySet.length === 1 && initialPolicySet[0] === "2.5.29.32.0" && explicitPolicyIndicator === false) userConstrPolicies = initialPolicySet;else { + if (authConstrPolicies.length === 1 && authConstrPolicies[0] === "2.5.29.32.0") userConstrPolicies = initialPolicySet;else { + for (let i = 0; i < authConstrPolicies.length; i++) { + for (let j = 0; j < initialPolicySet.length; j++) { + if (initialPolicySet[j] === authConstrPolicies[i] || initialPolicySet[j] === "2.5.29.32.0") { + userConstrPolicies.push(authConstrPolicies[i]); + break; + } + } + } + } + } //endregion + //region Combine output object + + const policyResult = { + result: userConstrPolicies.length > 0, + resultCode: 0, + resultMessage: userConstrPolicies.length > 0 ? "" : "Zero \"userConstrPolicies\" array, no intersections with \"authConstrPolicies\"", + authConstrPolicies, + userConstrPolicies, + explicitPolicyIndicator, + policyMappings, + certificatePath: _this3.certs + }; + if (userConstrPolicies.length === 0) return policyResult; //endregion + //endregion + //region Work with name constraints + //region Check a result from "policy checking" part + + if (policyResult.result === false) return policyResult; //endregion + //region Check all certificates, excluding "trust anchor" + + pathDepth = 1; + + for (let i = _this3.certs.length - 2; i >= 0; i--, pathDepth++) { + //region Support variables + let subjectAltNames = []; + let certPermittedSubtrees = []; + let certExcludedSubtrees = []; //endregion + + if ("extensions" in _this3.certs[i]) { + for (let j = 0; j < _this3.certs[i].extensions.length; j++) { + //region NameConstraints + if (_this3.certs[i].extensions[j].extnID === "2.5.29.30") { + if ("permittedSubtrees" in _this3.certs[i].extensions[j].parsedValue) certPermittedSubtrees = certPermittedSubtrees.concat(_this3.certs[i].extensions[j].parsedValue.permittedSubtrees); + if ("excludedSubtrees" in _this3.certs[i].extensions[j].parsedValue) certExcludedSubtrees = certExcludedSubtrees.concat(_this3.certs[i].extensions[j].parsedValue.excludedSubtrees); + } //endregion + //region SubjectAltName + + + if (_this3.certs[i].extensions[j].extnID === "2.5.29.17") subjectAltNames = subjectAltNames.concat(_this3.certs[i].extensions[j].parsedValue.altNames); //endregion + } + } //region Checking for "required name forms" + + + let formFound = requiredNameForms.length <= 0; + + for (let j = 0; j < requiredNameForms.length; j++) { + switch (requiredNameForms[j].base.type) { + case 4: + // directoryName + { + if (requiredNameForms[j].base.value.typesAndValues.length !== _this3.certs[i].subject.typesAndValues.length) continue; + formFound = true; + + for (let k = 0; k < _this3.certs[i].subject.typesAndValues.length; k++) { + if (_this3.certs[i].subject.typesAndValues[k].type !== requiredNameForms[j].base.value.typesAndValues[k].type) { + formFound = false; + break; + } + } + + if (formFound === true) break; + } + break; + + default: // ??? Probably here we should reject the certificate ??? + + } + } + + if (formFound === false) { + policyResult.result = false; + policyResult.resultCode = 21; + policyResult.resultMessage = "No neccessary name form found"; + throw policyResult; + } //endregion + //region Checking for "permited sub-trees" + //region Make groups for all types of constraints + + + const constrGroups = []; // Array of array for groupped constraints + + constrGroups[0] = []; // rfc822Name + + constrGroups[1] = []; // dNSName + + constrGroups[2] = []; // directoryName + + constrGroups[3] = []; // uniformResourceIdentifier + + constrGroups[4] = []; // iPAddress + + for (let j = 0; j < permittedSubtrees.length; j++) { + switch (permittedSubtrees[j].base.type) { + //region rfc822Name + case 1: + constrGroups[0].push(permittedSubtrees[j]); + break; + //endregion + //region dNSName + + case 2: + constrGroups[1].push(permittedSubtrees[j]); + break; + //endregion + //region directoryName + + case 4: + constrGroups[2].push(permittedSubtrees[j]); + break; + //endregion + //region uniformResourceIdentifier + + case 6: + constrGroups[3].push(permittedSubtrees[j]); + break; + //endregion + //region iPAddress + + case 7: + constrGroups[4].push(permittedSubtrees[j]); + break; + //endregion + //region default + + default: //endregion + + } + } //endregion + //region Check name constraints groupped by type, one-by-one + + + for (let p = 0; p < 5; p++) { + let groupPermitted = false; + let valueExists = false; + const group = constrGroups[p]; + + for (let j = 0; j < group.length; j++) { + switch (p) { + //region rfc822Name + case 0: + if (subjectAltNames.length > 0) { + for (let k = 0; k < subjectAltNames.length; k++) { + if (subjectAltNames[k].type === 1) // rfc822Name + { + valueExists = true; + groupPermitted = groupPermitted || compareRFC822Name(subjectAltNames[k].value, group[j].base.value); + } + } + } else // Try to find out "emailAddress" inside "subject" + { + for (let k = 0; k < _this3.certs[i].subject.typesAndValues.length; k++) { + if (_this3.certs[i].subject.typesAndValues[k].type === "1.2.840.113549.1.9.1" || // PKCS#9 e-mail address + _this3.certs[i].subject.typesAndValues[k].type === "0.9.2342.19200300.100.1.3") // RFC1274 "rfc822Mailbox" e-mail address + { + valueExists = true; + groupPermitted = groupPermitted || compareRFC822Name(_this3.certs[i].subject.typesAndValues[k].value.valueBlock.value, group[j].base.value); + } + } + } + + break; + //endregion + //region dNSName + + case 1: + if (subjectAltNames.length > 0) { + for (let k = 0; k < subjectAltNames.length; k++) { + if (subjectAltNames[k].type === 2) // dNSName + { + valueExists = true; + groupPermitted = groupPermitted || compareDNSName(subjectAltNames[k].value, group[j].base.value); + } + } + } + + break; + //endregion + //region directoryName + + case 2: + valueExists = true; + groupPermitted = compareDirectoryName(_this3.certs[i].subject, group[j].base.value); + break; + //endregion + //region uniformResourceIdentifier + + case 3: + if (subjectAltNames.length > 0) { + for (let k = 0; k < subjectAltNames.length; k++) { + if (subjectAltNames[k].type === 6) // uniformResourceIdentifier + { + valueExists = true; + groupPermitted = groupPermitted || compareUniformResourceIdentifier(subjectAltNames[k].value, group[j].base.value); + } + } + } + + break; + //endregion + //region iPAddress + + case 4: + if (subjectAltNames.length > 0) { + for (let k = 0; k < subjectAltNames.length; k++) { + if (subjectAltNames[k].type === 7) // iPAddress + { + valueExists = true; + groupPermitted = groupPermitted || compareIPAddress(subjectAltNames[k].value, group[j].base.value); + } + } + } + + break; + //endregion + //region default + + default: //endregion + + } + + if (groupPermitted) break; + } + + if (groupPermitted === false && group.length > 0 && valueExists) { + policyResult.result = false; + policyResult.resultCode = 41; + policyResult.resultMessage = "Failed to meet \"permitted sub-trees\" name constraint"; + throw policyResult; + } + } //endregion + //endregion + //region Checking for "excluded sub-trees" + + + let excluded = false; + + for (let j = 0; j < excludedSubtrees.length; j++) { + switch (excludedSubtrees[j].base.type) { + //region rfc822Name + case 1: + if (subjectAltNames.length >= 0) { + for (let k = 0; k < subjectAltNames.length; k++) { + if (subjectAltNames[k].type === 1) // rfc822Name + excluded = excluded || compareRFC822Name(subjectAltNames[k].value, excludedSubtrees[j].base.value); + } + } else // Try to find out "emailAddress" inside "subject" + { + for (let k = 0; k < _this3.certs[i].subject.typesAndValues.length; k++) { + if (_this3.certs[i].subject.typesAndValues[k].type === "1.2.840.113549.1.9.1" || // PKCS#9 e-mail address + _this3.certs[i].subject.typesAndValues[k].type === "0.9.2342.19200300.100.1.3") // RFC1274 "rfc822Mailbox" e-mail address + excluded = excluded || compareRFC822Name(_this3.certs[i].subject.typesAndValues[k].value.valueBlock.value, excludedSubtrees[j].base.value); + } + } + + break; + //endregion + //region dNSName + + case 2: + if (subjectAltNames.length > 0) { + for (let k = 0; k < subjectAltNames.length; k++) { + if (subjectAltNames[k].type === 2) // dNSName + excluded = excluded || compareDNSName(subjectAltNames[k].value, excludedSubtrees[j].base.value); + } + } + + break; + //endregion + //region directoryName + + case 4: + excluded = excluded || compareDirectoryName(_this3.certs[i].subject, excludedSubtrees[j].base.value); + break; + //endregion + //region uniformResourceIdentifier + + case 6: + if (subjectAltNames.length > 0) { + for (let k = 0; k < subjectAltNames.length; k++) { + if (subjectAltNames[k].type === 6) // uniformResourceIdentifier + excluded = excluded || compareUniformResourceIdentifier(subjectAltNames[k].value, excludedSubtrees[j].base.value); + } + } + + break; + //endregion + //region iPAddress + + case 7: + if (subjectAltNames.length > 0) { + for (let k = 0; k < subjectAltNames.length; k++) { + if (subjectAltNames[k].type === 7) // iPAddress + excluded = excluded || compareIPAddress(subjectAltNames[k].value, excludedSubtrees[j].base.value); + } + } + + break; + //endregion + //region default + + default: // No action, but probably here we need to create a warning for "malformed constraint" + //endregion + + } + + if (excluded) break; + } + + if (excluded === true) { + policyResult.result = false; + policyResult.resultCode = 42; + policyResult.resultMessage = "Failed to meet \"excluded sub-trees\" name constraint"; + throw policyResult; + } //endregion + //region Append "cert_..._subtrees" to "..._subtrees" + + + permittedSubtrees = permittedSubtrees.concat(certPermittedSubtrees); + excludedSubtrees = excludedSubtrees.concat(certExcludedSubtrees); //endregion + } //endregion + + + return policyResult; //endregion + } catch (error) { + if (error instanceof Object) { + if ("resultMessage" in error) return error; + + if ("message" in error) { + return { + result: false, + resultCode: -1, + resultMessage: error.message + }; + } + } + + return { + result: false, + resultCode: -1, + resultMessage: error + }; + } + })(); + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = CertificateChainValidationEngine; + +},{"./common.js":110,"pvutils":113}],21:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _PolicyInformation = _interopRequireDefault(require("./PolicyInformation.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC5280 + */ +class CertificatePolicies { + //********************************************************************************** + + /** + * Constructor for CertificatePolicies class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {Array.} + * @desc certificatePolicies + */ + this.certificatePolicies = (0, _pvutils.getParametersValue)(parameters, "certificatePolicies", CertificatePolicies.defaultValues("certificatePolicies")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "certificatePolicies": + return []; + + default: + throw new Error(`Invalid member name for CertificatePolicies class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * certificatePolicies ::= SEQUENCE SIZE (1..MAX) OF PolicyInformation + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [certificatePolicies] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [new asn1js.Repeated({ + name: names.certificatePolicies || "", + value: _PolicyInformation.default.schema() + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["certificatePolicies"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, CertificatePolicies.schema({ + names: { + certificatePolicies: "certificatePolicies" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for CertificatePolicies"); //endregion + //region Get internal properties from parsed schema + + this.certificatePolicies = Array.from(asn1.result.certificatePolicies, element => new _PolicyInformation.default({ + schema: element + })); //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Construct and return new ASN.1 schema for this object + return new asn1js.Sequence({ + value: Array.from(this.certificatePolicies, element => element.toSchema()) + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + return { + certificatePolicies: Array.from(this.certificatePolicies, element => element.toJSON()) + }; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = CertificatePolicies; + +},{"./PolicyInformation.js":72,"asn1js":112,"pvutils":113}],22:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _common = require("./common.js"); + +var _AlgorithmIdentifier = _interopRequireDefault(require("./AlgorithmIdentifier.js")); + +var _RelativeDistinguishedNames = _interopRequireDefault(require("./RelativeDistinguishedNames.js")); + +var _Time = _interopRequireDefault(require("./Time.js")); + +var _RevokedCertificate = _interopRequireDefault(require("./RevokedCertificate.js")); + +var _Extensions = _interopRequireDefault(require("./Extensions.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** +function tbsCertList(parameters = {}) { + //TBSCertList ::= SEQUENCE { + // version Version OPTIONAL, + // -- if present, MUST be v2 + // signature AlgorithmIdentifier, + // issuer Name, + // thisUpdate Time, + // nextUpdate Time OPTIONAL, + // revokedCertificates SEQUENCE OF SEQUENCE { + // userCertificate CertificateSerialNumber, + // revocationDate Time, + // crlEntryExtensions Extensions OPTIONAL + // -- if present, version MUST be v2 + // } OPTIONAL, + // crlExtensions [0] EXPLICIT Extensions OPTIONAL + // -- if present, version MUST be v2 + //} + + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [tbsCertListVersion] + * @property {string} [signature] + * @property {string} [issuer] + * @property {string} [tbsCertListThisUpdate] + * @property {string} [tbsCertListNextUpdate] + * @property {string} [tbsCertListRevokedCertificates] + * @property {string} [crlExtensions] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "tbsCertList", + value: [new asn1js.Integer({ + optional: true, + name: names.tbsCertListVersion || "tbsCertList.version", + value: 2 + }), // EXPLICIT integer value (v2) + _AlgorithmIdentifier.default.schema(names.signature || { + names: { + blockName: "tbsCertList.signature" + } + }), _RelativeDistinguishedNames.default.schema(names.issuer || { + names: { + blockName: "tbsCertList.issuer" + } + }), _Time.default.schema(names.tbsCertListThisUpdate || { + names: { + utcTimeName: "tbsCertList.thisUpdate", + generalTimeName: "tbsCertList.thisUpdate" + } + }), _Time.default.schema(names.tbsCertListNextUpdate || { + names: { + utcTimeName: "tbsCertList.nextUpdate", + generalTimeName: "tbsCertList.nextUpdate" + } + }, true), new asn1js.Sequence({ + optional: true, + value: [new asn1js.Repeated({ + name: names.tbsCertListRevokedCertificates || "tbsCertList.revokedCertificates", + value: new asn1js.Sequence({ + value: [new asn1js.Integer(), _Time.default.schema(), _Extensions.default.schema({}, true)] + }) + })] + }), new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: [_Extensions.default.schema(names.crlExtensions || { + names: { + blockName: "tbsCertList.extensions" + } + })] + }) // EXPLICIT SEQUENCE value + ] + }); +} //************************************************************************************** + +/** + * Class from RFC5280 + */ + + +class CertificateRevocationList { + //********************************************************************************** + + /** + * Constructor for Attribute class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {ArrayBuffer} + * @desc tbs + */ + this.tbs = (0, _pvutils.getParametersValue)(parameters, "tbs", CertificateRevocationList.defaultValues("tbs")); + /** + * @type {number} + * @desc version + */ + + this.version = (0, _pvutils.getParametersValue)(parameters, "version", CertificateRevocationList.defaultValues("version")); + /** + * @type {AlgorithmIdentifier} + * @desc signature + */ + + this.signature = (0, _pvutils.getParametersValue)(parameters, "signature", CertificateRevocationList.defaultValues("signature")); + /** + * @type {RelativeDistinguishedNames} + * @desc issuer + */ + + this.issuer = (0, _pvutils.getParametersValue)(parameters, "issuer", CertificateRevocationList.defaultValues("issuer")); + /** + * @type {Time} + * @desc thisUpdate + */ + + this.thisUpdate = (0, _pvutils.getParametersValue)(parameters, "thisUpdate", CertificateRevocationList.defaultValues("thisUpdate")); + if ("nextUpdate" in parameters) + /** + * @type {Time} + * @desc nextUpdate + */ + this.nextUpdate = (0, _pvutils.getParametersValue)(parameters, "nextUpdate", CertificateRevocationList.defaultValues("nextUpdate")); + if ("revokedCertificates" in parameters) + /** + * @type {Array.} + * @desc revokedCertificates + */ + this.revokedCertificates = (0, _pvutils.getParametersValue)(parameters, "revokedCertificates", CertificateRevocationList.defaultValues("revokedCertificates")); + if ("crlExtensions" in parameters) + /** + * @type {Extensions} + * @desc crlExtensions + */ + this.crlExtensions = (0, _pvutils.getParametersValue)(parameters, "crlExtensions", CertificateRevocationList.defaultValues("crlExtensions")); + /** + * @type {AlgorithmIdentifier} + * @desc signatureAlgorithm + */ + + this.signatureAlgorithm = (0, _pvutils.getParametersValue)(parameters, "signatureAlgorithm", CertificateRevocationList.defaultValues("signatureAlgorithm")); + /** + * @type {BitString} + * @desc signatureValue + */ + + this.signatureValue = (0, _pvutils.getParametersValue)(parameters, "signatureValue", CertificateRevocationList.defaultValues("signatureValue")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "tbs": + return new ArrayBuffer(0); + + case "version": + return 1; + + case "signature": + return new _AlgorithmIdentifier.default(); + + case "issuer": + return new _RelativeDistinguishedNames.default(); + + case "thisUpdate": + return new _Time.default(); + + case "nextUpdate": + return new _Time.default(); + + case "revokedCertificates": + return []; + + case "crlExtensions": + return new _Extensions.default(); + + case "signatureAlgorithm": + return new _AlgorithmIdentifier.default(); + + case "signatureValue": + return new asn1js.BitString(); + + default: + throw new Error(`Invalid member name for CertificateRevocationList class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * CertificateList ::= SEQUENCE { + * tbsCertList TBSCertList, + * signatureAlgorithm AlgorithmIdentifier, + * signatureValue BIT STRING } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [signatureAlgorithm] + * @property {string} [signatureValue] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "CertificateList", + value: [tbsCertList(parameters), _AlgorithmIdentifier.default.schema(names.signatureAlgorithm || { + names: { + blockName: "signatureAlgorithm" + } + }), new asn1js.BitString({ + name: names.signatureValue || "signatureValue" + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["tbsCertList", "tbsCertList.version", "tbsCertList.signature", "tbsCertList.issuer", "tbsCertList.thisUpdate", "tbsCertList.nextUpdate", "tbsCertList.revokedCertificates", "tbsCertList.extensions", "signatureAlgorithm", "signatureValue"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, CertificateRevocationList.schema()); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for CertificateRevocationList"); //endregion + //region Get internal properties from parsed schema + // noinspection JSUnresolvedVariable + + this.tbs = asn1.result.tbsCertList.valueBeforeDecode; + if ("tbsCertList.version" in asn1.result) this.version = asn1.result["tbsCertList.version"].valueBlock.valueDec; + this.signature = new _AlgorithmIdentifier.default({ + schema: asn1.result["tbsCertList.signature"] + }); + this.issuer = new _RelativeDistinguishedNames.default({ + schema: asn1.result["tbsCertList.issuer"] + }); + this.thisUpdate = new _Time.default({ + schema: asn1.result["tbsCertList.thisUpdate"] + }); + if ("tbsCertList.nextUpdate" in asn1.result) this.nextUpdate = new _Time.default({ + schema: asn1.result["tbsCertList.nextUpdate"] + }); + if ("tbsCertList.revokedCertificates" in asn1.result) this.revokedCertificates = Array.from(asn1.result["tbsCertList.revokedCertificates"], element => new _RevokedCertificate.default({ + schema: element + })); + if ("tbsCertList.extensions" in asn1.result) this.crlExtensions = new _Extensions.default({ + schema: asn1.result["tbsCertList.extensions"] + }); + this.signatureAlgorithm = new _AlgorithmIdentifier.default({ + schema: asn1.result.signatureAlgorithm + }); + this.signatureValue = asn1.result.signatureValue; //endregion + } //********************************************************************************** + + + encodeTBS() { + //region Create array for output sequence + const outputArray = []; + if (this.version !== CertificateRevocationList.defaultValues("version")) outputArray.push(new asn1js.Integer({ + value: this.version + })); + outputArray.push(this.signature.toSchema()); + outputArray.push(this.issuer.toSchema()); + outputArray.push(this.thisUpdate.toSchema()); + if ("nextUpdate" in this) outputArray.push(this.nextUpdate.toSchema()); + + if ("revokedCertificates" in this) { + outputArray.push(new asn1js.Sequence({ + value: Array.from(this.revokedCertificates, element => element.toSchema()) + })); + } + + if ("crlExtensions" in this) { + outputArray.push(new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: [this.crlExtensions.toSchema()] + })); + } //endregion + + + return new asn1js.Sequence({ + value: outputArray + }); + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema(encodeFlag = false) { + //region Decode stored TBS value + let tbsSchema; + + if (encodeFlag === false) { + if (this.tbs.length === 0) // No stored TBS part + return CertificateRevocationList.schema(); + tbsSchema = asn1js.fromBER(this.tbs).result; + } //endregion + //region Create TBS schema via assembling from TBS parts + else tbsSchema = this.encodeTBS(); //endregion + //region Construct and return new ASN.1 schema for this object + + + return new asn1js.Sequence({ + value: [tbsSchema, this.signatureAlgorithm.toSchema(), this.signatureValue] + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + const object = { + tbs: (0, _pvutils.bufferToHexCodes)(this.tbs, 0, this.tbs.byteLength), + signature: this.signature.toJSON(), + issuer: this.issuer.toJSON(), + thisUpdate: this.thisUpdate.toJSON(), + signatureAlgorithm: this.signatureAlgorithm.toJSON(), + signatureValue: this.signatureValue.toJSON() + }; + if (this.version !== CertificateRevocationList.defaultValues("version")) object.version = this.version; + if ("nextUpdate" in this) object.nextUpdate = this.nextUpdate.toJSON(); + if ("revokedCertificates" in this) object.revokedCertificates = Array.from(this.revokedCertificates, element => element.toJSON()); + if ("crlExtensions" in this) object.crlExtensions = this.crlExtensions.toJSON(); + return object; + } //********************************************************************************** + + + isCertificateRevoked(certificate) { + //region Check that issuer of the input certificate is the same with issuer of this CRL + if (this.issuer.isEqual(certificate.issuer) === false) return false; //endregion + //region Check that there are revoked certificates in this CRL + + if ("revokedCertificates" in this === false) return false; //endregion + //region Search for input certificate in revoked certificates array + + var _iteratorNormalCompletion = true; + var _didIteratorError = false; + var _iteratorError = undefined; + + try { + for (var _iterator = this.revokedCertificates[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { + const revokedCertificate = _step.value; + if (revokedCertificate.userCertificate.isEqual(certificate.serialNumber)) return true; + } //endregion + + } catch (err) { + _didIteratorError = true; + _iteratorError = err; + } finally { + try { + if (!_iteratorNormalCompletion && _iterator.return != null) { + _iterator.return(); + } + } finally { + if (_didIteratorError) { + throw _iteratorError; + } + } + } + + return false; + } //********************************************************************************** + + /** + * Make a signature for existing CRL data + * @param {Object} privateKey Private key for "subjectPublicKeyInfo" structure + * @param {string} [hashAlgorithm] Hashing algorithm. Default SHA-1 + */ + + + sign(privateKey, hashAlgorithm = "SHA-1") { + //region Initial checking + //region Get a private key from function parameter + if (typeof privateKey === "undefined") return Promise.reject("Need to provide a private key for signing"); //endregion + //endregion + //region Initial variables + + let sequence = Promise.resolve(); + let parameters; + const engine = (0, _common.getEngine)(); //endregion + //region Get a "default parameters" for current algorithm and set correct signature algorithm + + sequence = sequence.then(() => engine.subtle.getSignatureParameters(privateKey, hashAlgorithm)); + sequence = sequence.then(result => { + parameters = result.parameters; + this.signature = result.signatureAlgorithm; + this.signatureAlgorithm = result.signatureAlgorithm; + }); //endregion + //region Create TBS data for signing + + sequence = sequence.then(() => { + this.tbs = this.encodeTBS().toBER(false); + }); //endregion + //region Signing TBS data on provided private key + + sequence = sequence.then(() => engine.subtle.signWithPrivateKey(this.tbs, privateKey, parameters)); + sequence = sequence.then(result => { + this.signatureValue = new asn1js.BitString({ + valueHex: result + }); + }); //endregion + + return sequence; + } //********************************************************************************** + + /** + * Verify existing signature + * @param {{[issuerCertificate]: Object, [publicKeyInfo]: Object}} parameters + * @returns {*} + */ + + + verify(parameters = {}) { + //region Global variables + let sequence = Promise.resolve(); + let subjectPublicKeyInfo = -1; + const engine = (0, _common.getEngine)(); //endregion + //region Get information about CRL issuer certificate + + if ("issuerCertificate" in parameters) // "issuerCertificate" must be of type "Certificate" + { + subjectPublicKeyInfo = parameters.issuerCertificate.subjectPublicKeyInfo; // The CRL issuer name and "issuerCertificate" subject name are not equal + + if (this.issuer.isEqual(parameters.issuerCertificate.subject) === false) return Promise.resolve(false); + } //region In case if there is only public key during verification + + + if ("publicKeyInfo" in parameters) subjectPublicKeyInfo = parameters.publicKeyInfo; // Must be of type "PublicKeyInfo" + //endregion + + if ("subjectPublicKey" in subjectPublicKeyInfo === false) return Promise.reject("Issuer's certificate must be provided as an input parameter"); //endregion + //region Check the CRL for unknown critical extensions + + if ("crlExtensions" in this) { + var _iteratorNormalCompletion2 = true; + var _didIteratorError2 = false; + var _iteratorError2 = undefined; + + try { + for (var _iterator2 = this.crlExtensions.extensions[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { + const extension = _step2.value; + + if (extension.critical) { + // We can not be sure that unknown extension has no value for CRL signature + if ("parsedValue" in extension === false) return Promise.resolve(false); + } + } + } catch (err) { + _didIteratorError2 = true; + _iteratorError2 = err; + } finally { + try { + if (!_iteratorNormalCompletion2 && _iterator2.return != null) { + _iterator2.return(); + } + } finally { + if (_didIteratorError2) { + throw _iteratorError2; + } + } + } + } //endregion + + + sequence = sequence.then(() => engine.subtle.verifyWithPublicKey(this.tbs, this.signatureValue, subjectPublicKeyInfo, this.signatureAlgorithm)); + return sequence; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = CertificateRevocationList; + +},{"./AlgorithmIdentifier.js":4,"./Extensions.js":39,"./RelativeDistinguishedNames.js":89,"./RevokedCertificate.js":94,"./Time.js":107,"./common.js":110,"asn1js":112,"pvutils":113}],23:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _Certificate = _interopRequireDefault(require("./Certificate.js")); + +var _AttributeCertificateV = _interopRequireDefault(require("./AttributeCertificateV1.js")); + +var _AttributeCertificateV2 = _interopRequireDefault(require("./AttributeCertificateV2.js")); + +var _OtherCertificateFormat = _interopRequireDefault(require("./OtherCertificateFormat.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC5652 + */ +class CertificateSet { + //********************************************************************************** + + /** + * Constructor for CertificateSet class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {Array} + * @desc certificates + */ + this.certificates = (0, _pvutils.getParametersValue)(parameters, "certificates", CertificateSet.defaultValues("certificates")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "certificates": + return []; + + default: + throw new Error(`Invalid member name for Attribute class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * CertificateSet ::= SET OF CertificateChoices + * + * CertificateChoices ::= CHOICE { + * certificate Certificate, + * extendedCertificate [0] IMPLICIT ExtendedCertificate, -- Obsolete + * v1AttrCert [1] IMPLICIT AttributeCertificateV1, -- Obsolete + * v2AttrCert [2] IMPLICIT AttributeCertificateV2, + * other [3] IMPLICIT OtherCertificateFormat } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Set({ + name: names.blockName || "", + value: [new asn1js.Repeated({ + name: names.certificates || "certificates", + value: new asn1js.Choice({ + value: [_Certificate.default.schema(), new asn1js.Constructed({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: [new asn1js.Any()] + }), // JUST A STUB + new asn1js.Constructed({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + + }, + value: _AttributeCertificateV.default.schema().valueBlock.value + }), new asn1js.Constructed({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 2 // [2] + + }, + value: _AttributeCertificateV2.default.schema().valueBlock.value + }), new asn1js.Constructed({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 3 // [3] + + }, + value: _OtherCertificateFormat.default.schema().valueBlock.value + })] + }) + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["certificates"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, CertificateSet.schema()); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for CertificateSet"); //endregion + //region Get internal properties from parsed schema + + this.certificates = Array.from(asn1.result.certificates || [], element => { + const initialTagNumber = element.idBlock.tagNumber; + if (element.idBlock.tagClass === 1) return new _Certificate.default({ + schema: element + }); //region Making "Sequence" from "Constructed" value + + const elementSequence = new asn1js.Sequence({ + value: element.valueBlock.value + }); //endregion + + switch (initialTagNumber) { + case 1: + return new _AttributeCertificateV.default({ + schema: elementSequence + }); + + case 2: + return new _AttributeCertificateV2.default({ + schema: elementSequence + }); + + case 3: + return new _OtherCertificateFormat.default({ + schema: elementSequence + }); + + case 0: + default: + } + + return element; + }); //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Construct and return new ASN.1 schema for this object + return new asn1js.Set({ + value: Array.from(this.certificates, element => { + switch (true) { + case element instanceof _Certificate.default: + return element.toSchema(); + + case element instanceof _AttributeCertificateV.default: + return new asn1js.Constructed({ + idBlock: { + tagClass: 3, + tagNumber: 1 // [1] + + }, + value: element.toSchema().valueBlock.value + }); + + case element instanceof _AttributeCertificateV2.default: + return new asn1js.Constructed({ + idBlock: { + tagClass: 3, + tagNumber: 2 // [2] + + }, + value: element.toSchema().valueBlock.value + }); + + case element instanceof _OtherCertificateFormat.default: + return new asn1js.Constructed({ + idBlock: { + tagClass: 3, + tagNumber: 3 // [3] + + }, + value: element.toSchema().valueBlock.value + }); + + default: + } + + return element; + }) + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + return { + certificates: Array.from(this.certificates, element => element.toJSON()) + }; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = CertificateSet; + +},{"./AttributeCertificateV1.js":7,"./AttributeCertificateV2.js":8,"./Certificate.js":19,"./OtherCertificateFormat.js":60,"asn1js":112,"pvutils":113}],24:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from "[MS-WCCE]: Windows Client Certificate Enrollment Protocol" + */ +class CertificateTemplate { + //********************************************************************************** + + /** + * Constructor for CertificateTemplate class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {string} + * @desc templateID + */ + this.templateID = (0, _pvutils.getParametersValue)(parameters, "templateID", CertificateTemplate.defaultValues("templateID")); + if ("templateMajorVersion" in parameters) + /** + * @type {number} + * @desc templateMajorVersion + */ + this.templateMajorVersion = (0, _pvutils.getParametersValue)(parameters, "templateMajorVersion", CertificateTemplate.defaultValues("templateMajorVersion")); + if ("templateMinorVersion" in parameters) + /** + * @type {number} + * @desc templateMinorVersion + */ + this.templateMinorVersion = (0, _pvutils.getParametersValue)(parameters, "templateMinorVersion", CertificateTemplate.defaultValues("templateMinorVersion")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "templateID": + return ""; + + case "templateMajorVersion": + case "templateMinorVersion": + return 0; + + default: + throw new Error(`Invalid member name for CertificateTemplate class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * CertificateTemplateOID ::= SEQUENCE { + * templateID OBJECT IDENTIFIER, + * templateMajorVersion INTEGER (0..4294967295) OPTIONAL, + * templateMinorVersion INTEGER (0..4294967295) OPTIONAL + * } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [templateID] + * @property {string} [templateMajorVersion] + * @property {string} [templateMinorVersion] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [new asn1js.ObjectIdentifier({ + name: names.templateID || "" + }), new asn1js.Integer({ + name: names.templateMajorVersion || "", + optional: true + }), new asn1js.Integer({ + name: names.templateMinorVersion || "", + optional: true + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["templateID", "templateMajorVersion", "templateMinorVersion"]); //endregion + //region Check the schema is valid + + let asn1 = asn1js.compareSchema(schema, schema, CertificateTemplate.schema({ + names: { + templateID: "templateID", + templateMajorVersion: "templateMajorVersion", + templateMinorVersion: "templateMinorVersion" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for CertificateTemplate"); //endregion + //region Get internal properties from parsed schema + + this.templateID = asn1.result.templateID.valueBlock.toString(); + if ("templateMajorVersion" in asn1.result) this.templateMajorVersion = asn1.result.templateMajorVersion.valueBlock.valueDec; + if ("templateMinorVersion" in asn1.result) this.templateMinorVersion = asn1.result.templateMinorVersion.valueBlock.valueDec; //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Create array for output sequence + const outputArray = []; + outputArray.push(new asn1js.ObjectIdentifier({ + value: this.templateID + })); + if ("templateMajorVersion" in this) outputArray.push(new asn1js.Integer({ + value: this.templateMajorVersion + })); + if ("templateMinorVersion" in this) outputArray.push(new asn1js.Integer({ + value: this.templateMinorVersion + })); //endregion + //region Construct and return new ASN.1 schema for this object + + return new asn1js.Sequence({ + value: outputArray + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + const object = { + extnID: this.templateID + }; + if ("templateMajorVersion" in this) object.templateMajorVersion = this.templateMajorVersion; + if ("templateMinorVersion" in this) object.templateMinorVersion = this.templateMinorVersion; + return object; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = CertificateTemplate; + +},{"asn1js":112,"pvutils":113}],25:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _common = require("./common.js"); + +var _PublicKeyInfo = _interopRequireDefault(require("./PublicKeyInfo.js")); + +var _RelativeDistinguishedNames = _interopRequireDefault(require("./RelativeDistinguishedNames.js")); + +var _AlgorithmIdentifier = _interopRequireDefault(require("./AlgorithmIdentifier.js")); + +var _Attribute = _interopRequireDefault(require("./Attribute.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** +function CertificationRequestInfo(parameters = {}) { + //CertificationRequestInfo ::= SEQUENCE { + // version INTEGER { v1(0) } (v1,...), + // subject Name, + // subjectPKInfo SubjectPublicKeyInfo{{ PKInfoAlgorithms }}, + // attributes [0] Attributes{{ CRIAttributes }} + //} + + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [CertificationRequestInfo] + * @property {string} [CertificationRequestInfoVersion] + * @property {string} [subject] + * @property {string} [CertificationRequestInfoAttributes] + * @property {string} [attributes] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.CertificationRequestInfo || "CertificationRequestInfo", + value: [new asn1js.Integer({ + name: names.CertificationRequestInfoVersion || "CertificationRequestInfo.version" + }), _RelativeDistinguishedNames.default.schema(names.subject || { + names: { + blockName: "CertificationRequestInfo.subject" + } + }), _PublicKeyInfo.default.schema({ + names: { + blockName: "CertificationRequestInfo.subjectPublicKeyInfo" + } + }), new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: [new asn1js.Repeated({ + optional: true, + // Because OpenSSL makes wrong "attributes" field + name: names.CertificationRequestInfoAttributes || "CertificationRequestInfo.attributes", + value: _Attribute.default.schema(names.attributes || {}) + })] + })] + }); +} //************************************************************************************** + +/** + * Class from RFC2986 + */ + + +class CertificationRequest { + //********************************************************************************** + + /** + * Constructor for Attribute class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {ArrayBuffer} + * @desc tbs + */ + this.tbs = (0, _pvutils.getParametersValue)(parameters, "tbs", CertificationRequest.defaultValues("tbs")); + /** + * @type {number} + * @desc version + */ + + this.version = (0, _pvutils.getParametersValue)(parameters, "version", CertificationRequest.defaultValues("version")); + /** + * @type {RelativeDistinguishedNames} + * @desc subject + */ + + this.subject = (0, _pvutils.getParametersValue)(parameters, "subject", CertificationRequest.defaultValues("subject")); + /** + * @type {PublicKeyInfo} + * @desc subjectPublicKeyInfo + */ + + this.subjectPublicKeyInfo = (0, _pvutils.getParametersValue)(parameters, "subjectPublicKeyInfo", CertificationRequest.defaultValues("subjectPublicKeyInfo")); + if ("attributes" in parameters) + /** + * @type {Array.} + * @desc attributes + */ + this.attributes = (0, _pvutils.getParametersValue)(parameters, "attributes", CertificationRequest.defaultValues("attributes")); + /** + * @type {AlgorithmIdentifier} + * @desc signatureAlgorithm + */ + + this.signatureAlgorithm = (0, _pvutils.getParametersValue)(parameters, "signatureAlgorithm", CertificationRequest.defaultValues("signatureAlgorithm")); + /** + * @type {BitString} + * @desc signatureAlgorithm + */ + + this.signatureValue = (0, _pvutils.getParametersValue)(parameters, "signatureValue", CertificationRequest.defaultValues("signatureValue")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "tbs": + return new ArrayBuffer(0); + + case "version": + return 0; + + case "subject": + return new _RelativeDistinguishedNames.default(); + + case "subjectPublicKeyInfo": + return new _PublicKeyInfo.default(); + + case "attributes": + return []; + + case "signatureAlgorithm": + return new _AlgorithmIdentifier.default(); + + case "signatureValue": + return new asn1js.BitString(); + + default: + throw new Error(`Invalid member name for CertificationRequest class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * CertificationRequest ::= SEQUENCE { + * certificationRequestInfo CertificationRequestInfo, + * signatureAlgorithm AlgorithmIdentifier{{ SignatureAlgorithms }}, + * signature BIT STRING + * } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [certificationRequestInfo] + * @property {string} [signatureAlgorithm] + * @property {string} [signatureValue] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + value: [CertificationRequestInfo(names.certificationRequestInfo || {}), new asn1js.Sequence({ + name: names.signatureAlgorithm || "signatureAlgorithm", + value: [new asn1js.ObjectIdentifier(), new asn1js.Any({ + optional: true + })] + }), new asn1js.BitString({ + name: names.signatureValue || "signatureValue" + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["CertificationRequestInfo", "CertificationRequestInfo.version", "CertificationRequestInfo.subject", "CertificationRequestInfo.subjectPublicKeyInfo", "CertificationRequestInfo.attributes", "signatureAlgorithm", "signatureValue"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, CertificationRequest.schema()); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for CertificationRequest"); //endregion + //region Get internal properties from parsed schema + + this.tbs = asn1.result.CertificationRequestInfo.valueBeforeDecode; + this.version = asn1.result["CertificationRequestInfo.version"].valueBlock.valueDec; + this.subject = new _RelativeDistinguishedNames.default({ + schema: asn1.result["CertificationRequestInfo.subject"] + }); + this.subjectPublicKeyInfo = new _PublicKeyInfo.default({ + schema: asn1.result["CertificationRequestInfo.subjectPublicKeyInfo"] + }); + if ("CertificationRequestInfo.attributes" in asn1.result) this.attributes = Array.from(asn1.result["CertificationRequestInfo.attributes"], element => new _Attribute.default({ + schema: element + })); + this.signatureAlgorithm = new _AlgorithmIdentifier.default({ + schema: asn1.result.signatureAlgorithm + }); + this.signatureValue = asn1.result.signatureValue; //endregion + } //********************************************************************************** + + /** + * Aux function making ASN1js Sequence from current TBS + * @returns {Sequence} + */ + + + encodeTBS() { + //region Create array for output sequence + const outputArray = [new asn1js.Integer({ + value: this.version + }), this.subject.toSchema(), this.subjectPublicKeyInfo.toSchema()]; + + if ("attributes" in this) { + outputArray.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: Array.from(this.attributes, element => element.toSchema()) + })); + } //endregion + + + return new asn1js.Sequence({ + value: outputArray + }); + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema(encodeFlag = false) { + //region Decode stored TBS value + let tbsSchema; + + if (encodeFlag === false) { + if (this.tbs.byteLength === 0) // No stored TBS part + return CertificationRequest.schema(); + tbsSchema = asn1js.fromBER(this.tbs).result; + } //endregion + //region Create TBS schema via assembling from TBS parts + else tbsSchema = this.encodeTBS(); //endregion + //region Construct and return new ASN.1 schema for this object + + + return new asn1js.Sequence({ + value: [tbsSchema, this.signatureAlgorithm.toSchema(), this.signatureValue] + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + const object = { + tbs: (0, _pvutils.bufferToHexCodes)(this.tbs, 0, this.tbs.byteLength), + version: this.version, + subject: this.subject.toJSON(), + subjectPublicKeyInfo: this.subjectPublicKeyInfo.toJSON(), + signatureAlgorithm: this.signatureAlgorithm.toJSON(), + signatureValue: this.signatureValue.toJSON() + }; + if ("attributes" in this) object.attributes = Array.from(this.attributes, element => element.toJSON()); + return object; + } //********************************************************************************** + + /** + * Makes signature for currect certification request + * @param {Object} privateKey WebCrypto private key + * @param {string} [hashAlgorithm=SHA-1] String representing current hashing algorithm + */ + + + sign(privateKey, hashAlgorithm = "SHA-1") { + //region Initial checking + //region Get a private key from function parameter + if (typeof privateKey === "undefined") return Promise.reject("Need to provide a private key for signing"); //endregion + //endregion + //region Initial variables + + let sequence = Promise.resolve(); + let parameters; + const engine = (0, _common.getEngine)(); //endregion + //region Get a "default parameters" for current algorithm and set correct signature algorithm + + sequence = sequence.then(() => engine.subtle.getSignatureParameters(privateKey, hashAlgorithm)); + sequence = sequence.then(result => { + parameters = result.parameters; + this.signatureAlgorithm = result.signatureAlgorithm; + }); //endregion + //region Create TBS data for signing + + sequence = sequence.then(() => { + this.tbs = this.encodeTBS().toBER(false); + }); //endregion + //region Signing TBS data on provided private key + + sequence = sequence.then(() => engine.subtle.signWithPrivateKey(this.tbs, privateKey, parameters)); + sequence = sequence.then(result => { + this.signatureValue = new asn1js.BitString({ + valueHex: result + }); + }); //endregion + + return sequence; + } //********************************************************************************** + + /** + * Verify existing certification request signature + * @returns {*} + */ + + + verify() { + return (0, _common.getEngine)().subtle.verifyWithPublicKey(this.tbs, this.signatureValue, this.subjectPublicKeyInfo, this.signatureAlgorithm); + } //********************************************************************************** + + /** + * Importing public key for current certificate request + */ + + + getPublicKey(parameters = null) { + return (0, _common.getEngine)().getPublicKey(this.subjectPublicKeyInfo, this.signatureAlgorithm, parameters); + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = CertificationRequest; + +},{"./AlgorithmIdentifier.js":4,"./Attribute.js":6,"./PublicKeyInfo.js":78,"./RelativeDistinguishedNames.js":89,"./common.js":110,"asn1js":112,"pvutils":113}],26:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC5652 + */ +class ContentInfo { + //********************************************************************************** + + /** + * Constructor for ContentInfo class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {string} + * @desc contentType + */ + this.contentType = (0, _pvutils.getParametersValue)(parameters, "contentType", ContentInfo.defaultValues("contentType")); + /** + * @type {Any} + * @desc content + */ + + this.content = (0, _pvutils.getParametersValue)(parameters, "content", ContentInfo.defaultValues("content")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "contentType": + return ""; + + case "content": + return new asn1js.Any(); + + default: + throw new Error(`Invalid member name for ContentInfo class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + + + static compareWithDefault(memberName, memberValue) { + switch (memberName) { + case "contentType": + return memberValue === ""; + + case "content": + return memberValue instanceof asn1js.Any; + + default: + throw new Error(`Invalid member name for ContentInfo class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * ContentInfo ::= SEQUENCE { + * contentType ContentType, + * content [0] EXPLICIT ANY DEFINED BY contentType } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [contentType] + * @property {string} [content] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + if ("optional" in names === false) names.optional = false; + return new asn1js.Sequence({ + name: names.blockName || "ContentInfo", + optional: names.optional, + value: [new asn1js.ObjectIdentifier({ + name: names.contentType || "contentType" + }), new asn1js.Constructed({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: [new asn1js.Any({ + name: names.content || "content" + })] // EXPLICIT ANY value + + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["contentType", "content"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, ContentInfo.schema()); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for ContentInfo"); //endregion + //region Get internal properties from parsed schema + + this.contentType = asn1.result.contentType.valueBlock.toString(); + this.content = asn1.result.content; //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Construct and return new ASN.1 schema for this object + return new asn1js.Sequence({ + value: [new asn1js.ObjectIdentifier({ + value: this.contentType + }), new asn1js.Constructed({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: [this.content] // EXPLICIT ANY value + + })] + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + const object = { + contentType: this.contentType + }; + if (!(this.content instanceof asn1js.Any)) object.content = this.content.toJSON(); + return object; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = ContentInfo; + +},{"asn1js":112,"pvutils":113}],27:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _common = require("./common.js"); + +var _PublicKeyInfo = _interopRequireDefault(require("./PublicKeyInfo.js")); + +var _PrivateKeyInfo = _interopRequireDefault(require("./PrivateKeyInfo.js")); + +var _AlgorithmIdentifier = _interopRequireDefault(require("./AlgorithmIdentifier.js")); + +var _EncryptedContentInfo = _interopRequireDefault(require("./EncryptedContentInfo.js")); + +var _RSASSAPSSParams = _interopRequireDefault(require("./RSASSAPSSParams.js")); + +var _PBKDF2Params = _interopRequireDefault(require("./PBKDF2Params.js")); + +var _PBES2Params = _interopRequireDefault(require("./PBES2Params.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Making MAC key using algorithm described in B.2 of PKCS#12 standard. + */ +function makePKCS12B2Key(cryptoEngine, hashAlgorithm, keyLength, password, salt, iterationCount) { + //region Initial variables + let u; + let v; + const result = []; //endregion + //region Get "u" and "v" values + + switch (hashAlgorithm.toUpperCase()) { + case "SHA-1": + u = 20; // 160 + + v = 64; // 512 + + break; + + case "SHA-256": + u = 32; // 256 + + v = 64; // 512 + + break; + + case "SHA-384": + u = 48; // 384 + + v = 128; // 1024 + + break; + + case "SHA-512": + u = 64; // 512 + + v = 128; // 1024 + + break; + + default: + throw new Error("Unsupported hashing algorithm"); + } //endregion + //region Main algorithm making key + //region Transform password to UTF-8 like string + + + const passwordViewInitial = new Uint8Array(password); + const passwordTransformed = new ArrayBuffer(password.byteLength * 2 + 2); + const passwordTransformedView = new Uint8Array(passwordTransformed); + + for (let i = 0; i < passwordViewInitial.length; i++) { + passwordTransformedView[i * 2] = 0x00; + passwordTransformedView[i * 2 + 1] = passwordViewInitial[i]; + } + + passwordTransformedView[passwordTransformedView.length - 2] = 0x00; + passwordTransformedView[passwordTransformedView.length - 1] = 0x00; + password = passwordTransformed.slice(0); //endregion + //region Construct a string D (the "diversifier") by concatenating v/8 copies of ID + + const D = new ArrayBuffer(v); + const dView = new Uint8Array(D); + + for (let i = 0; i < D.byteLength; i++) dView[i] = 3; // The ID value equal to "3" for MACing (see B.3 of standard) + //endregion + //region Concatenate copies of the salt together to create a string S of length v * ceil(s / v) bytes (the final copy of the salt may be trunacted to create S) + + + const saltLength = salt.byteLength; + const sLen = v * Math.ceil(saltLength / v); + const S = new ArrayBuffer(sLen); + const sView = new Uint8Array(S); + const saltView = new Uint8Array(salt); + + for (let i = 0; i < sLen; i++) sView[i] = saltView[i % saltLength]; //endregion + //region Concatenate copies of the password together to create a string P of length v * ceil(p / v) bytes (the final copy of the password may be truncated to create P) + + + const passwordLength = password.byteLength; + const pLen = v * Math.ceil(passwordLength / v); + const P = new ArrayBuffer(pLen); + const pView = new Uint8Array(P); + const passwordView = new Uint8Array(password); + + for (let i = 0; i < pLen; i++) pView[i] = passwordView[i % passwordLength]; //endregion + //region Set I=S||P to be the concatenation of S and P + + + const sPlusPLength = S.byteLength + P.byteLength; + let I = new ArrayBuffer(sPlusPLength); + let iView = new Uint8Array(I); + iView.set(sView); + iView.set(pView, sView.length); //endregion + //region Set c=ceil(n / u) + + const c = Math.ceil((keyLength >> 3) / u); //endregion + //region Initial variables + + let internalSequence = Promise.resolve(I); //endregion + //region For i=1, 2, ..., c, do the following: + + for (let i = 0; i <= c; i++) { + internalSequence = internalSequence.then(_I => { + //region Create contecanetion of D and I + const dAndI = new ArrayBuffer(D.byteLength + _I.byteLength); + const dAndIView = new Uint8Array(dAndI); + dAndIView.set(dView); + dAndIView.set(iView, dView.length); //endregion + + return dAndI; + }); //region Make "iterationCount" rounds of hashing + + for (let j = 0; j < iterationCount; j++) internalSequence = internalSequence.then(roundBuffer => cryptoEngine.digest({ + name: hashAlgorithm + }, new Uint8Array(roundBuffer))); //endregion + + + internalSequence = internalSequence.then(roundBuffer => { + //region Concatenate copies of Ai to create a string B of length v bits (the final copy of Ai may be truncated to create B) + const B = new ArrayBuffer(v); + const bView = new Uint8Array(B); + + for (let j = 0; j < B.byteLength; j++) bView[j] = roundBuffer[j % roundBuffer.length]; //endregion + //region Make new I value + + + const k = Math.ceil(saltLength / v) + Math.ceil(passwordLength / v); + const iRound = []; + let sliceStart = 0; + let sliceLength = v; + + for (let j = 0; j < k; j++) { + const chunk = Array.from(new Uint8Array(I.slice(sliceStart, sliceStart + sliceLength))); + sliceStart += v; + if (sliceStart + v > I.byteLength) sliceLength = I.byteLength - sliceStart; + let x = 0x1ff; + + for (let l = B.byteLength - 1; l >= 0; l--) { + x >>= 8; + x += bView[l] + chunk[l]; + chunk[l] = x & 0xff; + } + + iRound.push(...chunk); + } + + I = new ArrayBuffer(iRound.length); + iView = new Uint8Array(I); + iView.set(iRound); //endregion + + result.push(...new Uint8Array(roundBuffer)); + return I; + }); + } //endregion + //region Initialize final key + + + internalSequence = internalSequence.then(() => { + const resultBuffer = new ArrayBuffer(keyLength >> 3); + const resultView = new Uint8Array(resultBuffer); + resultView.set(new Uint8Array(result).slice(0, keyLength >> 3)); + return resultBuffer; + }); //endregion + //endregion + + return internalSequence; +} //************************************************************************************** + +/** + * Default cryptographic engine for Web Cryptography API + */ + + +class CryptoEngine { + //********************************************************************************** + + /** + * Constructor for CryptoEngine class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {Object} + * @desc Usually here we are expecting "window.crypto" or an equivalent from custom "crypto engine" + */ + this.crypto = (0, _pvutils.getParametersValue)(parameters, "crypto", {}); + /** + * @type {Object} + * @desc Usually here we are expecting "window.crypto.subtle" or an equivalent from custom "crypto engine" + */ + + this.subtle = (0, _pvutils.getParametersValue)(parameters, "subtle", {}); + /** + * @type {string} + * @desc Name of the "crypto engine" + */ + + this.name = (0, _pvutils.getParametersValue)(parameters, "name", ""); //endregion + } //********************************************************************************** + + /** + * Import WebCrypto keys from different formats + * @param {string} format + * @param {ArrayBuffer|Uint8Array} keyData + * @param {Object} algorithm + * @param {boolean} extractable + * @param {Array} keyUsages + * @returns {Promise} + */ + + + importKey(format, keyData, algorithm, extractable, keyUsages) { + //region Initial variables + let jwk = {}; //endregion + //region Change "keyData" type if needed + + if (keyData instanceof Uint8Array) keyData = keyData.buffer; //endregion + + switch (format.toLowerCase()) { + case "raw": + return this.subtle.importKey("raw", keyData, algorithm, extractable, keyUsages); + + case "spki": + { + const asn1 = asn1js.fromBER(keyData); + if (asn1.offset === -1) return Promise.reject("Incorrect keyData"); + const publicKeyInfo = new _PublicKeyInfo.default(); + + try { + publicKeyInfo.fromSchema(asn1.result); + } catch (ex) { + return Promise.reject("Incorrect keyData"); + } // noinspection FallThroughInSwitchStatementJS + + + switch (algorithm.name.toUpperCase()) { + case "RSA-PSS": + { + //region Get information about used hash function + switch (algorithm.hash.name.toUpperCase()) { + case "SHA-1": + jwk.alg = "PS1"; + break; + + case "SHA-256": + jwk.alg = "PS256"; + break; + + case "SHA-384": + jwk.alg = "PS384"; + break; + + case "SHA-512": + jwk.alg = "PS512"; + break; + + default: + return Promise.reject(`Incorrect hash algorithm: ${algorithm.hash.name.toUpperCase()}`); + } //endregion + + } + // break omitted + + case "RSASSA-PKCS1-V1_5": + { + keyUsages = ["verify"]; // Override existing keyUsages value since the key is a public key + + jwk.kty = "RSA"; + jwk.ext = extractable; + jwk.key_ops = keyUsages; + if (publicKeyInfo.algorithm.algorithmId !== "1.2.840.113549.1.1.1") return Promise.reject(`Incorrect public key algorithm: ${publicKeyInfo.algorithm.algorithmId}`); //region Get information about used hash function + + if ("alg" in jwk === false) { + switch (algorithm.hash.name.toUpperCase()) { + case "SHA-1": + jwk.alg = "RS1"; + break; + + case "SHA-256": + jwk.alg = "RS256"; + break; + + case "SHA-384": + jwk.alg = "RS384"; + break; + + case "SHA-512": + jwk.alg = "RS512"; + break; + + default: + return Promise.reject(`Incorrect public key algorithm: ${publicKeyInfo.algorithm.algorithmId}`); + } + } //endregion + //region Create RSA Public Key elements + + + const publicKeyJSON = publicKeyInfo.toJSON(); + + for (var _i = 0, _Object$keys = Object.keys(publicKeyJSON); _i < _Object$keys.length; _i++) { + const key = _Object$keys[_i]; + jwk[key] = publicKeyJSON[key]; + } //endregion + + } + break; + + case "ECDSA": + keyUsages = ["verify"]; + // Override existing keyUsages value since the key is a public key + // break omitted + + case "ECDH": + { + //region Initial variables + jwk = { + kty: "EC", + ext: extractable, + key_ops: keyUsages + }; //endregion + //region Get information about algorithm + + if (publicKeyInfo.algorithm.algorithmId !== "1.2.840.10045.2.1") return Promise.reject(`Incorrect public key algorithm: ${publicKeyInfo.algorithm.algorithmId}`); //endregion + //region Create ECDSA Public Key elements + + const publicKeyJSON = publicKeyInfo.toJSON(); + + for (var _i2 = 0, _Object$keys2 = Object.keys(publicKeyJSON); _i2 < _Object$keys2.length; _i2++) { + const key = _Object$keys2[_i2]; + jwk[key] = publicKeyJSON[key]; + } //endregion + + } + break; + + case "RSA-OAEP": + { + jwk.kty = "RSA"; + jwk.ext = extractable; + jwk.key_ops = keyUsages; + if (this.name.toLowerCase() === "safari") jwk.alg = "RSA-OAEP";else { + switch (algorithm.hash.name.toUpperCase()) { + case "SHA-1": + jwk.alg = "RSA-OAEP"; + break; + + case "SHA-256": + jwk.alg = "RSA-OAEP-256"; + break; + + case "SHA-384": + jwk.alg = "RSA-OAEP-384"; + break; + + case "SHA-512": + jwk.alg = "RSA-OAEP-512"; + break; + + default: + return Promise.reject(`Incorrect public key algorithm: ${publicKeyInfo.algorithm.algorithmId}`); + } + } //region Create ECDSA Public Key elements + + const publicKeyJSON = publicKeyInfo.toJSON(); + + for (var _i3 = 0, _Object$keys3 = Object.keys(publicKeyJSON); _i3 < _Object$keys3.length; _i3++) { + const key = _Object$keys3[_i3]; + jwk[key] = publicKeyJSON[key]; + } //endregion + + } + break; + + default: + return Promise.reject(`Incorrect algorithm name: ${algorithm.name.toUpperCase()}`); + } + } + break; + + case "pkcs8": + { + const privateKeyInfo = new _PrivateKeyInfo.default(); //region Parse "PrivateKeyInfo" object + + const asn1 = asn1js.fromBER(keyData); + if (asn1.offset === -1) return Promise.reject("Incorrect keyData"); + + try { + privateKeyInfo.fromSchema(asn1.result); + } catch (ex) { + return Promise.reject("Incorrect keyData"); + } + + if ("parsedKey" in privateKeyInfo === false) return Promise.reject("Incorrect keyData"); //endregion + // noinspection FallThroughInSwitchStatementJS + // noinspection FallThroughInSwitchStatementJS + + switch (algorithm.name.toUpperCase()) { + case "RSA-PSS": + { + //region Get information about used hash function + switch (algorithm.hash.name.toUpperCase()) { + case "SHA-1": + jwk.alg = "PS1"; + break; + + case "SHA-256": + jwk.alg = "PS256"; + break; + + case "SHA-384": + jwk.alg = "PS384"; + break; + + case "SHA-512": + jwk.alg = "PS512"; + break; + + default: + return Promise.reject(`Incorrect hash algorithm: ${algorithm.hash.name.toUpperCase()}`); + } //endregion + + } + // break omitted + + case "RSASSA-PKCS1-V1_5": + { + keyUsages = ["sign"]; // Override existing keyUsages value since the key is a private key + + jwk.kty = "RSA"; + jwk.ext = extractable; + jwk.key_ops = keyUsages; //region Get information about used hash function + + if (privateKeyInfo.privateKeyAlgorithm.algorithmId !== "1.2.840.113549.1.1.1") return Promise.reject(`Incorrect private key algorithm: ${privateKeyInfo.privateKeyAlgorithm.algorithmId}`); //endregion + //region Get information about used hash function + + if ("alg" in jwk === false) { + switch (algorithm.hash.name.toUpperCase()) { + case "SHA-1": + jwk.alg = "RS1"; + break; + + case "SHA-256": + jwk.alg = "RS256"; + break; + + case "SHA-384": + jwk.alg = "RS384"; + break; + + case "SHA-512": + jwk.alg = "RS512"; + break; + + default: + return Promise.reject(`Incorrect hash algorithm: ${algorithm.hash.name.toUpperCase()}`); + } + } //endregion + //region Create RSA Private Key elements + + + const privateKeyJSON = privateKeyInfo.toJSON(); + + for (var _i4 = 0, _Object$keys4 = Object.keys(privateKeyJSON); _i4 < _Object$keys4.length; _i4++) { + const key = _Object$keys4[_i4]; + jwk[key] = privateKeyJSON[key]; + } //endregion + + } + break; + + case "ECDSA": + keyUsages = ["sign"]; + // Override existing keyUsages value since the key is a private key + // break omitted + + case "ECDH": + { + //region Initial variables + jwk = { + kty: "EC", + ext: extractable, + key_ops: keyUsages + }; //endregion + //region Get information about used hash function + + if (privateKeyInfo.privateKeyAlgorithm.algorithmId !== "1.2.840.10045.2.1") return Promise.reject(`Incorrect algorithm: ${privateKeyInfo.privateKeyAlgorithm.algorithmId}`); //endregion + //region Create ECDSA Private Key elements + + const privateKeyJSON = privateKeyInfo.toJSON(); + + for (var _i5 = 0, _Object$keys5 = Object.keys(privateKeyJSON); _i5 < _Object$keys5.length; _i5++) { + const key = _Object$keys5[_i5]; + jwk[key] = privateKeyJSON[key]; + } //endregion + + } + break; + + case "RSA-OAEP": + { + jwk.kty = "RSA"; + jwk.ext = extractable; + jwk.key_ops = keyUsages; //region Get information about used hash function + + if (this.name.toLowerCase() === "safari") jwk.alg = "RSA-OAEP";else { + switch (algorithm.hash.name.toUpperCase()) { + case "SHA-1": + jwk.alg = "RSA-OAEP"; + break; + + case "SHA-256": + jwk.alg = "RSA-OAEP-256"; + break; + + case "SHA-384": + jwk.alg = "RSA-OAEP-384"; + break; + + case "SHA-512": + jwk.alg = "RSA-OAEP-512"; + break; + + default: + return Promise.reject(`Incorrect hash algorithm: ${algorithm.hash.name.toUpperCase()}`); + } + } //endregion + //region Create RSA Private Key elements + + const privateKeyJSON = privateKeyInfo.toJSON(); + + for (var _i6 = 0, _Object$keys6 = Object.keys(privateKeyJSON); _i6 < _Object$keys6.length; _i6++) { + const key = _Object$keys6[_i6]; + jwk[key] = privateKeyJSON[key]; + } //endregion + + } + break; + + default: + return Promise.reject(`Incorrect algorithm name: ${algorithm.name.toUpperCase()}`); + } + } + break; + + case "jwk": + jwk = keyData; + break; + + default: + return Promise.reject(`Incorrect format: ${format}`); + } //region Special case for Safari browser (since its acting not as WebCrypto standard describes) + + + if (this.name.toLowerCase() === "safari") { + // Try to use both ways - import using ArrayBuffer and pure JWK (for Safari Technology Preview) + return Promise.resolve().then(() => this.subtle.importKey("jwk", (0, _pvutils.stringToArrayBuffer)(JSON.stringify(jwk)), algorithm, extractable, keyUsages)).then(result => result, () => this.subtle.importKey("jwk", jwk, algorithm, extractable, keyUsages)); + } //endregion + + + return this.subtle.importKey("jwk", jwk, algorithm, extractable, keyUsages); + } //********************************************************************************** + + /** + * Export WebCrypto keys to different formats + * @param {string} format + * @param {Object} key + * @returns {Promise} + */ + + + exportKey(format, key) { + let sequence = this.subtle.exportKey("jwk", key); //region Currently Safari returns ArrayBuffer as JWK thus we need an additional transformation + + if (this.name.toLowerCase() === "safari") { + sequence = sequence.then(result => { + // Some additional checks for Safari Technology Preview + if (result instanceof ArrayBuffer) return JSON.parse((0, _pvutils.arrayBufferToString)(result)); + return result; + }); + } //endregion + + + switch (format.toLowerCase()) { + case "raw": + return this.subtle.exportKey("raw", key); + + case "spki": + sequence = sequence.then(result => { + const publicKeyInfo = new _PublicKeyInfo.default(); + + try { + publicKeyInfo.fromJSON(result); + } catch (ex) { + return Promise.reject("Incorrect key data"); + } + + return publicKeyInfo.toSchema().toBER(false); + }); + break; + + case "pkcs8": + sequence = sequence.then(result => { + const privateKeyInfo = new _PrivateKeyInfo.default(); + + try { + privateKeyInfo.fromJSON(result); + } catch (ex) { + return Promise.reject("Incorrect key data"); + } + + return privateKeyInfo.toSchema().toBER(false); + }); + break; + + case "jwk": + break; + + default: + return Promise.reject(`Incorrect format: ${format}`); + } + + return sequence; + } //********************************************************************************** + + /** + * Convert WebCrypto keys between different export formats + * @param {string} inputFormat + * @param {string} outputFormat + * @param {ArrayBuffer|Object} keyData + * @param {Object} algorithm + * @param {boolean} extractable + * @param {Array} keyUsages + * @returns {Promise} + */ + + + convert(inputFormat, outputFormat, keyData, algorithm, extractable, keyUsages) { + switch (inputFormat.toLowerCase()) { + case "raw": + switch (outputFormat.toLowerCase()) { + case "raw": + return Promise.resolve(keyData); + + case "spki": + return Promise.resolve().then(() => this.importKey("raw", keyData, algorithm, extractable, keyUsages)).then(result => this.exportKey("spki", result)); + + case "pkcs8": + return Promise.resolve().then(() => this.importKey("raw", keyData, algorithm, extractable, keyUsages)).then(result => this.exportKey("pkcs8", result)); + + case "jwk": + return Promise.resolve().then(() => this.importKey("raw", keyData, algorithm, extractable, keyUsages)).then(result => this.exportKey("jwk", result)); + + default: + return Promise.reject(`Incorrect outputFormat: ${outputFormat}`); + } + + case "spki": + switch (outputFormat.toLowerCase()) { + case "raw": + return Promise.resolve().then(() => this.importKey("spki", keyData, algorithm, extractable, keyUsages)).then(result => this.exportKey("raw", result)); + + case "spki": + return Promise.resolve(keyData); + + case "pkcs8": + return Promise.reject("Impossible to convert between SPKI/PKCS8"); + + case "jwk": + return Promise.resolve().then(() => this.importKey("spki", keyData, algorithm, extractable, keyUsages)).then(result => this.exportKey("jwk", result)); + + default: + return Promise.reject(`Incorrect outputFormat: ${outputFormat}`); + } + + case "pkcs8": + switch (outputFormat.toLowerCase()) { + case "raw": + return Promise.resolve().then(() => this.importKey("pkcs8", keyData, algorithm, extractable, keyUsages)).then(result => this.exportKey("raw", result)); + + case "spki": + return Promise.reject("Impossible to convert between SPKI/PKCS8"); + + case "pkcs8": + return Promise.resolve(keyData); + + case "jwk": + return Promise.resolve().then(() => this.importKey("pkcs8", keyData, algorithm, extractable, keyUsages)).then(result => this.exportKey("jwk", result)); + + default: + return Promise.reject(`Incorrect outputFormat: ${outputFormat}`); + } + + case "jwk": + switch (outputFormat.toLowerCase()) { + case "raw": + return Promise.resolve().then(() => this.importKey("jwk", keyData, algorithm, extractable, keyUsages)).then(result => this.exportKey("raw", result)); + + case "spki": + return Promise.resolve().then(() => this.importKey("jwk", keyData, algorithm, extractable, keyUsages)).then(result => this.exportKey("spki", result)); + + case "pkcs8": + return Promise.resolve().then(() => this.importKey("jwk", keyData, algorithm, extractable, keyUsages)).then(result => this.exportKey("pkcs8", result)); + + case "jwk": + return Promise.resolve(keyData); + + default: + return Promise.reject(`Incorrect outputFormat: ${outputFormat}`); + } + + default: + return Promise.reject(`Incorrect inputFormat: ${inputFormat}`); + } + } //********************************************************************************** + + /** + * Wrapper for standard function "encrypt" + * @param args + * @returns {Promise} + */ + + + encrypt(...args) { + return this.subtle.encrypt(...args); + } //********************************************************************************** + + /** + * Wrapper for standard function "decrypt" + * @param args + * @returns {Promise} + */ + + + decrypt(...args) { + return this.subtle.decrypt(...args); + } //********************************************************************************** + + /** + * Wrapper for standard function "sign" + * @param args + * @returns {Promise} + */ + + + sign(...args) { + return this.subtle.sign(...args); + } //********************************************************************************** + + /** + * Wrapper for standard function "verify" + * @param args + * @returns {Promise} + */ + + + verify(...args) { + return this.subtle.verify(...args); + } //********************************************************************************** + + /** + * Wrapper for standard function "digest" + * @param args + * @returns {Promise} + */ + + + digest(...args) { + return this.subtle.digest(...args); + } //********************************************************************************** + + /** + * Wrapper for standard function "generateKey" + * @param args + * @returns {Promise} + */ + + + generateKey(...args) { + return this.subtle.generateKey(...args); + } //********************************************************************************** + + /** + * Wrapper for standard function "deriveKey" + * @param args + * @returns {Promise} + */ + + + deriveKey(...args) { + return this.subtle.deriveKey(...args); + } //********************************************************************************** + + /** + * Wrapper for standard function "deriveBits" + * @param args + * @returns {Promise} + */ + + + deriveBits(...args) { + return this.subtle.deriveBits(...args); + } //********************************************************************************** + + /** + * Wrapper for standard function "wrapKey" + * @param args + * @returns {Promise} + */ + + + wrapKey(...args) { + return this.subtle.wrapKey(...args); + } //********************************************************************************** + + /** + * Wrapper for standard function "unwrapKey" + * @param args + * @returns {Promise} + */ + + + unwrapKey(...args) { + return this.subtle.unwrapKey(...args); + } //********************************************************************************** + + /** + * Initialize input Uint8Array by random values (with help from current "crypto engine") + * @param {!Uint8Array} view + * @returns {*} + */ + + + getRandomValues(view) { + if ("getRandomValues" in this.crypto === false) throw new Error("No support for getRandomValues"); + return this.crypto.getRandomValues(view); + } //********************************************************************************** + + /** + * Get WebCrypto algorithm by wel-known OID + * @param {string} oid well-known OID to search for + * @returns {Object} + */ + + + getAlgorithmByOID(oid) { + switch (oid) { + case "1.2.840.113549.1.1.1": + case "1.2.840.113549.1.1.5": + return { + name: "RSASSA-PKCS1-v1_5", + hash: { + name: "SHA-1" + } + }; + + case "1.2.840.113549.1.1.11": + return { + name: "RSASSA-PKCS1-v1_5", + hash: { + name: "SHA-256" + } + }; + + case "1.2.840.113549.1.1.12": + return { + name: "RSASSA-PKCS1-v1_5", + hash: { + name: "SHA-384" + } + }; + + case "1.2.840.113549.1.1.13": + return { + name: "RSASSA-PKCS1-v1_5", + hash: { + name: "SHA-512" + } + }; + + case "1.2.840.113549.1.1.10": + return { + name: "RSA-PSS" + }; + + case "1.2.840.113549.1.1.7": + return { + name: "RSA-OAEP" + }; + + case "1.2.840.10045.2.1": + case "1.2.840.10045.4.1": + return { + name: "ECDSA", + hash: { + name: "SHA-1" + } + }; + + case "1.2.840.10045.4.3.2": + return { + name: "ECDSA", + hash: { + name: "SHA-256" + } + }; + + case "1.2.840.10045.4.3.3": + return { + name: "ECDSA", + hash: { + name: "SHA-384" + } + }; + + case "1.2.840.10045.4.3.4": + return { + name: "ECDSA", + hash: { + name: "SHA-512" + } + }; + + case "1.3.133.16.840.63.0.2": + return { + name: "ECDH", + kdf: "SHA-1" + }; + + case "1.3.132.1.11.1": + return { + name: "ECDH", + kdf: "SHA-256" + }; + + case "1.3.132.1.11.2": + return { + name: "ECDH", + kdf: "SHA-384" + }; + + case "1.3.132.1.11.3": + return { + name: "ECDH", + kdf: "SHA-512" + }; + + case "2.16.840.1.101.3.4.1.2": + return { + name: "AES-CBC", + length: 128 + }; + + case "2.16.840.1.101.3.4.1.22": + return { + name: "AES-CBC", + length: 192 + }; + + case "2.16.840.1.101.3.4.1.42": + return { + name: "AES-CBC", + length: 256 + }; + + case "2.16.840.1.101.3.4.1.6": + return { + name: "AES-GCM", + length: 128 + }; + + case "2.16.840.1.101.3.4.1.26": + return { + name: "AES-GCM", + length: 192 + }; + + case "2.16.840.1.101.3.4.1.46": + return { + name: "AES-GCM", + length: 256 + }; + + case "2.16.840.1.101.3.4.1.4": + return { + name: "AES-CFB", + length: 128 + }; + + case "2.16.840.1.101.3.4.1.24": + return { + name: "AES-CFB", + length: 192 + }; + + case "2.16.840.1.101.3.4.1.44": + return { + name: "AES-CFB", + length: 256 + }; + + case "2.16.840.1.101.3.4.1.5": + return { + name: "AES-KW", + length: 128 + }; + + case "2.16.840.1.101.3.4.1.25": + return { + name: "AES-KW", + length: 192 + }; + + case "2.16.840.1.101.3.4.1.45": + return { + name: "AES-KW", + length: 256 + }; + + case "1.2.840.113549.2.7": + return { + name: "HMAC", + hash: { + name: "SHA-1" + } + }; + + case "1.2.840.113549.2.9": + return { + name: "HMAC", + hash: { + name: "SHA-256" + } + }; + + case "1.2.840.113549.2.10": + return { + name: "HMAC", + hash: { + name: "SHA-384" + } + }; + + case "1.2.840.113549.2.11": + return { + name: "HMAC", + hash: { + name: "SHA-512" + } + }; + + case "1.2.840.113549.1.9.16.3.5": + return { + name: "DH" + }; + + case "1.3.14.3.2.26": + return { + name: "SHA-1" + }; + + case "2.16.840.1.101.3.4.2.1": + return { + name: "SHA-256" + }; + + case "2.16.840.1.101.3.4.2.2": + return { + name: "SHA-384" + }; + + case "2.16.840.1.101.3.4.2.3": + return { + name: "SHA-512" + }; + + case "1.2.840.113549.1.5.12": + return { + name: "PBKDF2" + }; + //region Special case - OIDs for ECC curves + + case "1.2.840.10045.3.1.7": + return { + name: "P-256" + }; + + case "1.3.132.0.34": + return { + name: "P-384" + }; + + case "1.3.132.0.35": + return { + name: "P-521" + }; + //endregion + + default: + } + + return {}; + } //********************************************************************************** + + /** + * Get OID for each specific algorithm + * @param {Object} algorithm + * @returns {string} + */ + + + getOIDByAlgorithm(algorithm) { + let result = ""; + + switch (algorithm.name.toUpperCase()) { + case "RSASSA-PKCS1-V1_5": + switch (algorithm.hash.name.toUpperCase()) { + case "SHA-1": + result = "1.2.840.113549.1.1.5"; + break; + + case "SHA-256": + result = "1.2.840.113549.1.1.11"; + break; + + case "SHA-384": + result = "1.2.840.113549.1.1.12"; + break; + + case "SHA-512": + result = "1.2.840.113549.1.1.13"; + break; + + default: + } + + break; + + case "RSA-PSS": + result = "1.2.840.113549.1.1.10"; + break; + + case "RSA-OAEP": + result = "1.2.840.113549.1.1.7"; + break; + + case "ECDSA": + switch (algorithm.hash.name.toUpperCase()) { + case "SHA-1": + result = "1.2.840.10045.4.1"; + break; + + case "SHA-256": + result = "1.2.840.10045.4.3.2"; + break; + + case "SHA-384": + result = "1.2.840.10045.4.3.3"; + break; + + case "SHA-512": + result = "1.2.840.10045.4.3.4"; + break; + + default: + } + + break; + + case "ECDH": + switch (algorithm.kdf.toUpperCase()) { + // Non-standard addition - hash algorithm of KDF function + case "SHA-1": + result = "1.3.133.16.840.63.0.2"; // dhSinglePass-stdDH-sha1kdf-scheme + + break; + + case "SHA-256": + result = "1.3.132.1.11.1"; // dhSinglePass-stdDH-sha256kdf-scheme + + break; + + case "SHA-384": + result = "1.3.132.1.11.2"; // dhSinglePass-stdDH-sha384kdf-scheme + + break; + + case "SHA-512": + result = "1.3.132.1.11.3"; // dhSinglePass-stdDH-sha512kdf-scheme + + break; + + default: + } + + break; + + case "AES-CTR": + break; + + case "AES-CBC": + switch (algorithm.length) { + case 128: + result = "2.16.840.1.101.3.4.1.2"; + break; + + case 192: + result = "2.16.840.1.101.3.4.1.22"; + break; + + case 256: + result = "2.16.840.1.101.3.4.1.42"; + break; + + default: + } + + break; + + case "AES-CMAC": + break; + + case "AES-GCM": + switch (algorithm.length) { + case 128: + result = "2.16.840.1.101.3.4.1.6"; + break; + + case 192: + result = "2.16.840.1.101.3.4.1.26"; + break; + + case 256: + result = "2.16.840.1.101.3.4.1.46"; + break; + + default: + } + + break; + + case "AES-CFB": + switch (algorithm.length) { + case 128: + result = "2.16.840.1.101.3.4.1.4"; + break; + + case 192: + result = "2.16.840.1.101.3.4.1.24"; + break; + + case 256: + result = "2.16.840.1.101.3.4.1.44"; + break; + + default: + } + + break; + + case "AES-KW": + switch (algorithm.length) { + case 128: + result = "2.16.840.1.101.3.4.1.5"; + break; + + case 192: + result = "2.16.840.1.101.3.4.1.25"; + break; + + case 256: + result = "2.16.840.1.101.3.4.1.45"; + break; + + default: + } + + break; + + case "HMAC": + switch (algorithm.hash.name.toUpperCase()) { + case "SHA-1": + result = "1.2.840.113549.2.7"; + break; + + case "SHA-256": + result = "1.2.840.113549.2.9"; + break; + + case "SHA-384": + result = "1.2.840.113549.2.10"; + break; + + case "SHA-512": + result = "1.2.840.113549.2.11"; + break; + + default: + } + + break; + + case "DH": + result = "1.2.840.113549.1.9.16.3.5"; + break; + + case "SHA-1": + result = "1.3.14.3.2.26"; + break; + + case "SHA-256": + result = "2.16.840.1.101.3.4.2.1"; + break; + + case "SHA-384": + result = "2.16.840.1.101.3.4.2.2"; + break; + + case "SHA-512": + result = "2.16.840.1.101.3.4.2.3"; + break; + + case "CONCAT": + break; + + case "HKDF": + break; + + case "PBKDF2": + result = "1.2.840.113549.1.5.12"; + break; + //region Special case - OIDs for ECC curves + + case "P-256": + result = "1.2.840.10045.3.1.7"; + break; + + case "P-384": + result = "1.3.132.0.34"; + break; + + case "P-521": + result = "1.3.132.0.35"; + break; + //endregion + + default: + } + + return result; + } //********************************************************************************** + + /** + * Get default algorithm parameters for each kind of operation + * @param {string} algorithmName Algorithm name to get common parameters for + * @param {string} operation Kind of operation: "sign", "encrypt", "generatekey", "importkey", "exportkey", "verify" + * @returns {*} + */ + + + getAlgorithmParameters(algorithmName, operation) { + let result = { + algorithm: {}, + usages: [] + }; + + switch (algorithmName.toUpperCase()) { + case "RSASSA-PKCS1-V1_5": + switch (operation.toLowerCase()) { + case "generatekey": + result = { + algorithm: { + name: "RSASSA-PKCS1-v1_5", + modulusLength: 2048, + publicExponent: new Uint8Array([0x01, 0x00, 0x01]), + hash: { + name: "SHA-256" + } + }, + usages: ["sign", "verify"] + }; + break; + + case "verify": + case "sign": + case "importkey": + result = { + algorithm: { + name: "RSASSA-PKCS1-v1_5", + hash: { + name: "SHA-256" + } + }, + usages: ["verify"] // For importKey("pkcs8") usage must be "sign" only + + }; + break; + + case "exportkey": + default: + return { + algorithm: { + name: "RSASSA-PKCS1-v1_5" + }, + usages: [] + }; + } + + break; + + case "RSA-PSS": + switch (operation.toLowerCase()) { + case "sign": + case "verify": + result = { + algorithm: { + name: "RSA-PSS", + hash: { + name: "SHA-1" + }, + saltLength: 20 + }, + usages: ["sign", "verify"] + }; + break; + + case "generatekey": + result = { + algorithm: { + name: "RSA-PSS", + modulusLength: 2048, + publicExponent: new Uint8Array([0x01, 0x00, 0x01]), + hash: { + name: "SHA-1" + } + }, + usages: ["sign", "verify"] + }; + break; + + case "importkey": + result = { + algorithm: { + name: "RSA-PSS", + hash: { + name: "SHA-1" + } + }, + usages: ["verify"] // For importKey("pkcs8") usage must be "sign" only + + }; + break; + + case "exportkey": + default: + return { + algorithm: { + name: "RSA-PSS" + }, + usages: [] + }; + } + + break; + + case "RSA-OAEP": + switch (operation.toLowerCase()) { + case "encrypt": + case "decrypt": + result = { + algorithm: { + name: "RSA-OAEP" + }, + usages: ["encrypt", "decrypt"] + }; + break; + + case "generatekey": + result = { + algorithm: { + name: "RSA-OAEP", + modulusLength: 2048, + publicExponent: new Uint8Array([0x01, 0x00, 0x01]), + hash: { + name: "SHA-256" + } + }, + usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"] + }; + break; + + case "importkey": + result = { + algorithm: { + name: "RSA-OAEP", + hash: { + name: "SHA-256" + } + }, + usages: ["encrypt"] // encrypt for "spki" and decrypt for "pkcs8" + + }; + break; + + case "exportkey": + default: + return { + algorithm: { + name: "RSA-OAEP" + }, + usages: [] + }; + } + + break; + + case "ECDSA": + switch (operation.toLowerCase()) { + case "generatekey": + result = { + algorithm: { + name: "ECDSA", + namedCurve: "P-256" + }, + usages: ["sign", "verify"] + }; + break; + + case "importkey": + result = { + algorithm: { + name: "ECDSA", + namedCurve: "P-256" + }, + usages: ["verify"] // "sign" for "pkcs8" + + }; + break; + + case "verify": + case "sign": + result = { + algorithm: { + name: "ECDSA", + hash: { + name: "SHA-256" + } + }, + usages: ["sign"] + }; + break; + + default: + return { + algorithm: { + name: "ECDSA" + }, + usages: [] + }; + } + + break; + + case "ECDH": + switch (operation.toLowerCase()) { + case "exportkey": + case "importkey": + case "generatekey": + result = { + algorithm: { + name: "ECDH", + namedCurve: "P-256" + }, + usages: ["deriveKey", "deriveBits"] + }; + break; + + case "derivekey": + case "derivebits": + result = { + algorithm: { + name: "ECDH", + namedCurve: "P-256", + public: [] // Must be a "publicKey" + + }, + usages: ["encrypt", "decrypt"] + }; + break; + + default: + return { + algorithm: { + name: "ECDH" + }, + usages: [] + }; + } + + break; + + case "AES-CTR": + switch (operation.toLowerCase()) { + case "importkey": + case "exportkey": + case "generatekey": + result = { + algorithm: { + name: "AES-CTR", + length: 256 + }, + usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"] + }; + break; + + case "decrypt": + case "encrypt": + result = { + algorithm: { + name: "AES-CTR", + counter: new Uint8Array(16), + length: 10 + }, + usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"] + }; + break; + + default: + return { + algorithm: { + name: "AES-CTR" + }, + usages: [] + }; + } + + break; + + case "AES-CBC": + switch (operation.toLowerCase()) { + case "importkey": + case "exportkey": + case "generatekey": + result = { + algorithm: { + name: "AES-CBC", + length: 256 + }, + usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"] + }; + break; + + case "decrypt": + case "encrypt": + result = { + algorithm: { + name: "AES-CBC", + iv: this.getRandomValues(new Uint8Array(16)) // For "decrypt" the value should be replaced with value got on "encrypt" step + + }, + usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"] + }; + break; + + default: + return { + algorithm: { + name: "AES-CBC" + }, + usages: [] + }; + } + + break; + + case "AES-GCM": + switch (operation.toLowerCase()) { + case "importkey": + case "exportkey": + case "generatekey": + result = { + algorithm: { + name: "AES-GCM", + length: 256 + }, + usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"] + }; + break; + + case "decrypt": + case "encrypt": + result = { + algorithm: { + name: "AES-GCM", + iv: this.getRandomValues(new Uint8Array(16)) // For "decrypt" the value should be replaced with value got on "encrypt" step + + }, + usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"] + }; + break; + + default: + return { + algorithm: { + name: "AES-GCM" + }, + usages: [] + }; + } + + break; + + case "AES-KW": + switch (operation.toLowerCase()) { + case "importkey": + case "exportkey": + case "generatekey": + case "wrapkey": + case "unwrapkey": + result = { + algorithm: { + name: "AES-KW", + length: 256 + }, + usages: ["wrapKey", "unwrapKey"] + }; + break; + + default: + return { + algorithm: { + name: "AES-KW" + }, + usages: [] + }; + } + + break; + + case "HMAC": + switch (operation.toLowerCase()) { + case "sign": + case "verify": + result = { + algorithm: { + name: "HMAC" + }, + usages: ["sign", "verify"] + }; + break; + + case "importkey": + case "exportkey": + case "generatekey": + result = { + algorithm: { + name: "HMAC", + length: 32, + hash: { + name: "SHA-256" + } + }, + usages: ["sign", "verify"] + }; + break; + + default: + return { + algorithm: { + name: "HMAC" + }, + usages: [] + }; + } + + break; + + case "HKDF": + switch (operation.toLowerCase()) { + case "derivekey": + result = { + algorithm: { + name: "HKDF", + hash: "SHA-256", + salt: new Uint8Array([]), + info: new Uint8Array([]) + }, + usages: ["encrypt", "decrypt"] + }; + break; + + default: + return { + algorithm: { + name: "HKDF" + }, + usages: [] + }; + } + + break; + + case "PBKDF2": + switch (operation.toLowerCase()) { + case "derivekey": + result = { + algorithm: { + name: "PBKDF2", + hash: { + name: "SHA-256" + }, + salt: new Uint8Array([]), + iterations: 10000 + }, + usages: ["encrypt", "decrypt"] + }; + break; + + default: + return { + algorithm: { + name: "PBKDF2" + }, + usages: [] + }; + } + + break; + + default: + } + + return result; + } //********************************************************************************** + + /** + * Getting hash algorithm by signature algorithm + * @param {AlgorithmIdentifier} signatureAlgorithm Signature algorithm + * @returns {string} + */ + + + getHashAlgorithm(signatureAlgorithm) { + let result = ""; + + switch (signatureAlgorithm.algorithmId) { + case "1.2.840.10045.4.1": // ecdsa-with-SHA1 + + case "1.2.840.113549.1.1.5": + result = "SHA-1"; + break; + + case "1.2.840.10045.4.3.2": // ecdsa-with-SHA256 + + case "1.2.840.113549.1.1.11": + result = "SHA-256"; + break; + + case "1.2.840.10045.4.3.3": // ecdsa-with-SHA384 + + case "1.2.840.113549.1.1.12": + result = "SHA-384"; + break; + + case "1.2.840.10045.4.3.4": // ecdsa-with-SHA512 + + case "1.2.840.113549.1.1.13": + result = "SHA-512"; + break; + + case "1.2.840.113549.1.1.10": + // RSA-PSS + { + try { + const params = new _RSASSAPSSParams.default({ + schema: signatureAlgorithm.algorithmParams + }); + + if ("hashAlgorithm" in params) { + const algorithm = this.getAlgorithmByOID(params.hashAlgorithm.algorithmId); + if ("name" in algorithm === false) return ""; + result = algorithm.name; + } else result = "SHA-1"; + } catch (ex) {} + } + break; + + default: + } + + return result; + } //********************************************************************************** + + /** + * Specialized function encrypting "EncryptedContentInfo" object using parameters + * @param {Object} parameters + * @returns {Promise} + */ + + + encryptEncryptedContentInfo(parameters) { + //region Check for input parameters + if (parameters instanceof Object === false) return Promise.reject("Parameters must have type \"Object\""); + if ("password" in parameters === false) return Promise.reject("Absent mandatory parameter \"password\""); + if ("contentEncryptionAlgorithm" in parameters === false) return Promise.reject("Absent mandatory parameter \"contentEncryptionAlgorithm\""); + if ("hmacHashAlgorithm" in parameters === false) return Promise.reject("Absent mandatory parameter \"hmacHashAlgorithm\""); + if ("iterationCount" in parameters === false) return Promise.reject("Absent mandatory parameter \"iterationCount\""); + if ("contentToEncrypt" in parameters === false) return Promise.reject("Absent mandatory parameter \"contentToEncrypt\""); + if ("contentType" in parameters === false) return Promise.reject("Absent mandatory parameter \"contentType\""); + const contentEncryptionOID = this.getOIDByAlgorithm(parameters.contentEncryptionAlgorithm); + if (contentEncryptionOID === "") return Promise.reject("Wrong \"contentEncryptionAlgorithm\" value"); + const pbkdf2OID = this.getOIDByAlgorithm({ + name: "PBKDF2" + }); + if (pbkdf2OID === "") return Promise.reject("Can not find OID for PBKDF2"); + const hmacOID = this.getOIDByAlgorithm({ + name: "HMAC", + hash: { + name: parameters.hmacHashAlgorithm + } + }); + if (hmacOID === "") return Promise.reject(`Incorrect value for "hmacHashAlgorithm": ${parameters.hmacHashAlgorithm}`); //endregion + //region Initial variables + + let sequence = Promise.resolve(); + const ivBuffer = new ArrayBuffer(16); // For AES we need IV 16 bytes long + + const ivView = new Uint8Array(ivBuffer); + this.getRandomValues(ivView); + const saltBuffer = new ArrayBuffer(64); + const saltView = new Uint8Array(saltBuffer); + this.getRandomValues(saltView); + const contentView = new Uint8Array(parameters.contentToEncrypt); + const pbkdf2Params = new _PBKDF2Params.default({ + salt: new asn1js.OctetString({ + valueHex: saltBuffer + }), + iterationCount: parameters.iterationCount, + prf: new _AlgorithmIdentifier.default({ + algorithmId: hmacOID, + algorithmParams: new asn1js.Null() + }) + }); //endregion + //region Derive PBKDF2 key from "password" buffer + + sequence = sequence.then(() => { + const passwordView = new Uint8Array(parameters.password); + return this.importKey("raw", passwordView, "PBKDF2", false, ["deriveKey"]); + }, error => Promise.reject(error)); //endregion + //region Derive key for "contentEncryptionAlgorithm" + + sequence = sequence.then(result => this.deriveKey({ + name: "PBKDF2", + hash: { + name: parameters.hmacHashAlgorithm + }, + salt: saltView, + iterations: parameters.iterationCount + }, result, parameters.contentEncryptionAlgorithm, false, ["encrypt"]), error => Promise.reject(error)); //endregion + //region Encrypt content + + sequence = sequence.then(result => this.encrypt({ + name: parameters.contentEncryptionAlgorithm.name, + iv: ivView + }, result, contentView), error => Promise.reject(error)); //endregion + //region Store all parameters in EncryptedData object + + sequence = sequence.then(result => { + const pbes2Parameters = new _PBES2Params.default({ + keyDerivationFunc: new _AlgorithmIdentifier.default({ + algorithmId: pbkdf2OID, + algorithmParams: pbkdf2Params.toSchema() + }), + encryptionScheme: new _AlgorithmIdentifier.default({ + algorithmId: contentEncryptionOID, + algorithmParams: new asn1js.OctetString({ + valueHex: ivBuffer + }) + }) + }); + return new _EncryptedContentInfo.default({ + contentType: parameters.contentType, + contentEncryptionAlgorithm: new _AlgorithmIdentifier.default({ + algorithmId: "1.2.840.113549.1.5.13", + // pkcs5PBES2 + algorithmParams: pbes2Parameters.toSchema() + }), + encryptedContent: new asn1js.OctetString({ + valueHex: result + }) + }); + }, error => Promise.reject(error)); //endregion + + return sequence; + } //********************************************************************************** + + /** + * Decrypt data stored in "EncryptedContentInfo" object using parameters + * @param parameters + * @return {Promise} + */ + + + decryptEncryptedContentInfo(parameters) { + //region Check for input parameters + if (parameters instanceof Object === false) return Promise.reject("Parameters must have type \"Object\""); + if ("password" in parameters === false) return Promise.reject("Absent mandatory parameter \"password\""); + if ("encryptedContentInfo" in parameters === false) return Promise.reject("Absent mandatory parameter \"encryptedContentInfo\""); + if (parameters.encryptedContentInfo.contentEncryptionAlgorithm.algorithmId !== "1.2.840.113549.1.5.13") // pkcs5PBES2 + return Promise.reject(`Unknown "contentEncryptionAlgorithm": ${parameters.encryptedContentInfo.contentEncryptionAlgorithm.algorithmId}`); //endregion + //region Initial variables + + let sequence = Promise.resolve(); + let pbes2Parameters; + + try { + pbes2Parameters = new _PBES2Params.default({ + schema: parameters.encryptedContentInfo.contentEncryptionAlgorithm.algorithmParams + }); + } catch (ex) { + return Promise.reject("Incorrectly encoded \"pbes2Parameters\""); + } + + let pbkdf2Params; + + try { + pbkdf2Params = new _PBKDF2Params.default({ + schema: pbes2Parameters.keyDerivationFunc.algorithmParams + }); + } catch (ex) { + return Promise.reject("Incorrectly encoded \"pbkdf2Params\""); + } + + const contentEncryptionAlgorithm = this.getAlgorithmByOID(pbes2Parameters.encryptionScheme.algorithmId); + if ("name" in contentEncryptionAlgorithm === false) return Promise.reject(`Incorrect OID for "contentEncryptionAlgorithm": ${pbes2Parameters.encryptionScheme.algorithmId}`); + const ivBuffer = pbes2Parameters.encryptionScheme.algorithmParams.valueBlock.valueHex; + const ivView = new Uint8Array(ivBuffer); + const saltBuffer = pbkdf2Params.salt.valueBlock.valueHex; + const saltView = new Uint8Array(saltBuffer); + const iterationCount = pbkdf2Params.iterationCount; + let hmacHashAlgorithm = "SHA-1"; + + if ("prf" in pbkdf2Params) { + const algorithm = this.getAlgorithmByOID(pbkdf2Params.prf.algorithmId); + if ("name" in algorithm === false) return Promise.reject("Incorrect OID for HMAC hash algorithm"); + hmacHashAlgorithm = algorithm.hash.name; + } //endregion + //region Derive PBKDF2 key from "password" buffer + + + sequence = sequence.then(() => this.importKey("raw", parameters.password, "PBKDF2", false, ["deriveKey"]), error => Promise.reject(error)); //endregion + //region Derive key for "contentEncryptionAlgorithm" + + sequence = sequence.then(result => this.deriveKey({ + name: "PBKDF2", + hash: { + name: hmacHashAlgorithm + }, + salt: saltView, + iterations: iterationCount + }, result, contentEncryptionAlgorithm, false, ["decrypt"]), error => Promise.reject(error)); //endregion + //region Decrypt internal content using derived key + + sequence = sequence.then(result => { + //region Create correct data block for decryption + let dataBuffer = new ArrayBuffer(0); + if (parameters.encryptedContentInfo.encryptedContent.idBlock.isConstructed === false) dataBuffer = parameters.encryptedContentInfo.encryptedContent.valueBlock.valueHex;else { + var _iteratorNormalCompletion = true; + var _didIteratorError = false; + var _iteratorError = undefined; + + try { + for (var _iterator = parameters.encryptedContentInfo.encryptedContent.valueBlock.value[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { + const content = _step.value; + dataBuffer = (0, _pvutils.utilConcatBuf)(dataBuffer, content.valueBlock.valueHex); + } + } catch (err) { + _didIteratorError = true; + _iteratorError = err; + } finally { + try { + if (!_iteratorNormalCompletion && _iterator.return != null) { + _iterator.return(); + } + } finally { + if (_didIteratorError) { + throw _iteratorError; + } + } + } + } //endregion + + return this.decrypt({ + name: contentEncryptionAlgorithm.name, + iv: ivView + }, result, dataBuffer); + }, error => Promise.reject(error)); //endregion + + return sequence; + } //********************************************************************************** + + /** + * Stamping (signing) data using algorithm simular to HMAC + * @param {Object} parameters + * @return {Promise.|Promise} + */ + + + stampDataWithPassword(parameters) { + //region Check for input parameters + if (parameters instanceof Object === false) return Promise.reject("Parameters must have type \"Object\""); + if ("password" in parameters === false) return Promise.reject("Absent mandatory parameter \"password\""); + if ("hashAlgorithm" in parameters === false) return Promise.reject("Absent mandatory parameter \"hashAlgorithm\""); + if ("salt" in parameters === false) return Promise.reject("Absent mandatory parameter \"iterationCount\""); + if ("iterationCount" in parameters === false) return Promise.reject("Absent mandatory parameter \"salt\""); + if ("contentToStamp" in parameters === false) return Promise.reject("Absent mandatory parameter \"contentToStamp\""); //endregion + //region Choose correct length for HMAC key + + let length; + + switch (parameters.hashAlgorithm.toLowerCase()) { + case "sha-1": + length = 160; + break; + + case "sha-256": + length = 256; + break; + + case "sha-384": + length = 384; + break; + + case "sha-512": + length = 512; + break; + + default: + return Promise.reject(`Incorrect "parameters.hashAlgorithm" parameter: ${parameters.hashAlgorithm}`); + } //endregion + //region Initial variables + + + let sequence = Promise.resolve(); + const hmacAlgorithm = { + name: "HMAC", + length, + hash: { + name: parameters.hashAlgorithm + } + }; //endregion + //region Create PKCS#12 key for integrity checking + + sequence = sequence.then(() => makePKCS12B2Key(this, parameters.hashAlgorithm, length, parameters.password, parameters.salt, parameters.iterationCount)); //endregion + //region Import HMAC key + // noinspection JSCheckFunctionSignatures + + sequence = sequence.then(result => this.importKey("raw", new Uint8Array(result), hmacAlgorithm, false, ["sign"])); //endregion + //region Make signed HMAC value + + sequence = sequence.then(result => this.sign(hmacAlgorithm, result, new Uint8Array(parameters.contentToStamp)), error => Promise.reject(error)); //endregion + + return sequence; + } //********************************************************************************** + + + verifyDataStampedWithPassword(parameters) { + //region Check for input parameters + if (parameters instanceof Object === false) return Promise.reject("Parameters must have type \"Object\""); + if ("password" in parameters === false) return Promise.reject("Absent mandatory parameter \"password\""); + if ("hashAlgorithm" in parameters === false) return Promise.reject("Absent mandatory parameter \"hashAlgorithm\""); + if ("salt" in parameters === false) return Promise.reject("Absent mandatory parameter \"iterationCount\""); + if ("iterationCount" in parameters === false) return Promise.reject("Absent mandatory parameter \"salt\""); + if ("contentToVerify" in parameters === false) return Promise.reject("Absent mandatory parameter \"contentToVerify\""); + if ("signatureToVerify" in parameters === false) return Promise.reject("Absent mandatory parameter \"signatureToVerify\""); //endregion + //region Choose correct length for HMAC key + + let length; + + switch (parameters.hashAlgorithm.toLowerCase()) { + case "sha-1": + length = 160; + break; + + case "sha-256": + length = 256; + break; + + case "sha-384": + length = 384; + break; + + case "sha-512": + length = 512; + break; + + default: + return Promise.reject(`Incorrect "parameters.hashAlgorithm" parameter: ${parameters.hashAlgorithm}`); + } //endregion + //region Initial variables + + + let sequence = Promise.resolve(); + const hmacAlgorithm = { + name: "HMAC", + length, + hash: { + name: parameters.hashAlgorithm + } + }; //endregion + //region Create PKCS#12 key for integrity checking + + sequence = sequence.then(() => makePKCS12B2Key(this, parameters.hashAlgorithm, length, parameters.password, parameters.salt, parameters.iterationCount)); //endregion + //region Import HMAC key + // noinspection JSCheckFunctionSignatures + + sequence = sequence.then(result => this.importKey("raw", new Uint8Array(result), hmacAlgorithm, false, ["verify"])); //endregion + //region Make signed HMAC value + + sequence = sequence.then(result => this.verify(hmacAlgorithm, result, new Uint8Array(parameters.signatureToVerify), new Uint8Array(parameters.contentToVerify)), error => Promise.reject(error)); //endregion + + return sequence; + } //********************************************************************************** + + /** + * Get signature parameters by analyzing private key algorithm + * @param {Object} privateKey The private key user would like to use + * @param {string} [hashAlgorithm="SHA-1"] Hash algorithm user would like to use + * @return {Promise.|Promise} + */ + + + getSignatureParameters(privateKey, hashAlgorithm = "SHA-1") { + //region Check hashing algorithm + const oid = this.getOIDByAlgorithm({ + name: hashAlgorithm + }); + if (oid === "") return Promise.reject(`Unsupported hash algorithm: ${hashAlgorithm}`); //endregion + //region Initial variables + + const signatureAlgorithm = new _AlgorithmIdentifier.default(); //endregion + //region Get a "default parameters" for current algorithm + + const parameters = this.getAlgorithmParameters(privateKey.algorithm.name, "sign"); + parameters.algorithm.hash.name = hashAlgorithm; //endregion + //region Fill internal structures base on "privateKey" and "hashAlgorithm" + + switch (privateKey.algorithm.name.toUpperCase()) { + case "RSASSA-PKCS1-V1_5": + case "ECDSA": + signatureAlgorithm.algorithmId = this.getOIDByAlgorithm(parameters.algorithm); + break; + + case "RSA-PSS": + { + //region Set "saltLength" as a length (in octets) of hash function result + switch (hashAlgorithm.toUpperCase()) { + case "SHA-256": + parameters.algorithm.saltLength = 32; + break; + + case "SHA-384": + parameters.algorithm.saltLength = 48; + break; + + case "SHA-512": + parameters.algorithm.saltLength = 64; + break; + + default: + } //endregion + //region Fill "RSASSA_PSS_params" object + + + const paramsObject = {}; + + if (hashAlgorithm.toUpperCase() !== "SHA-1") { + const hashAlgorithmOID = this.getOIDByAlgorithm({ + name: hashAlgorithm + }); + if (hashAlgorithmOID === "") return Promise.reject(`Unsupported hash algorithm: ${hashAlgorithm}`); + paramsObject.hashAlgorithm = new _AlgorithmIdentifier.default({ + algorithmId: hashAlgorithmOID, + algorithmParams: new asn1js.Null() + }); + paramsObject.maskGenAlgorithm = new _AlgorithmIdentifier.default({ + algorithmId: "1.2.840.113549.1.1.8", + // MGF1 + algorithmParams: paramsObject.hashAlgorithm.toSchema() + }); + } + + if (parameters.algorithm.saltLength !== 20) paramsObject.saltLength = parameters.algorithm.saltLength; + const pssParameters = new _RSASSAPSSParams.default(paramsObject); //endregion + //region Automatically set signature algorithm + + signatureAlgorithm.algorithmId = "1.2.840.113549.1.1.10"; + signatureAlgorithm.algorithmParams = pssParameters.toSchema(); //endregion + } + break; + + default: + return Promise.reject(`Unsupported signature algorithm: ${privateKey.algorithm.name}`); + } //endregion + + + return Promise.resolve().then(() => ({ + signatureAlgorithm, + parameters + })); + } //********************************************************************************** + + /** + * Sign data with pre-defined private key + * @param {ArrayBuffer} data Data to be signed + * @param {Object} privateKey Private key to use + * @param {Object} parameters Parameters for used algorithm + * @return {Promise.|Promise} + */ + + + signWithPrivateKey(data, privateKey, parameters) { + return this.sign(parameters.algorithm, privateKey, new Uint8Array(data)).then(result => { + //region Special case for ECDSA algorithm + if (parameters.algorithm.name === "ECDSA") result = (0, _common.createCMSECDSASignature)(result); //endregion + + return result; + }, error => Promise.reject(`Signing error: ${error}`)); + } //********************************************************************************** + + + fillPublicKeyParameters(publicKeyInfo, signatureAlgorithm) { + const parameters = {}; //region Find signer's hashing algorithm + + const shaAlgorithm = this.getHashAlgorithm(signatureAlgorithm); + if (shaAlgorithm === "") return Promise.reject(`Unsupported signature algorithm: ${signatureAlgorithm.algorithmId}`); //endregion + //region Get information about public key algorithm and default parameters for import + + let algorithmId; + if (signatureAlgorithm.algorithmId === "1.2.840.113549.1.1.10") algorithmId = signatureAlgorithm.algorithmId;else algorithmId = publicKeyInfo.algorithm.algorithmId; + const algorithmObject = this.getAlgorithmByOID(algorithmId); + if ("name" in algorithmObject === "") return Promise.reject(`Unsupported public key algorithm: ${signatureAlgorithm.algorithmId}`); + parameters.algorithm = this.getAlgorithmParameters(algorithmObject.name, "importkey"); + if ("hash" in parameters.algorithm.algorithm) parameters.algorithm.algorithm.hash.name = shaAlgorithm; //region Special case for ECDSA + + if (algorithmObject.name === "ECDSA") { + //region Get information about named curve + let algorithmParamsChecked = false; + + if ("algorithmParams" in publicKeyInfo.algorithm === true) { + if ("idBlock" in publicKeyInfo.algorithm.algorithmParams) { + if (publicKeyInfo.algorithm.algorithmParams.idBlock.tagClass === 1 && publicKeyInfo.algorithm.algorithmParams.idBlock.tagNumber === 6) algorithmParamsChecked = true; + } + } + + if (algorithmParamsChecked === false) return Promise.reject("Incorrect type for ECDSA public key parameters"); + const curveObject = this.getAlgorithmByOID(publicKeyInfo.algorithm.algorithmParams.valueBlock.toString()); + if ("name" in curveObject === false) return Promise.reject(`Unsupported named curve algorithm: ${publicKeyInfo.algorithm.algorithmParams.valueBlock.toString()}`); //endregion + + parameters.algorithm.algorithm.namedCurve = curveObject.name; + } //endregion + //endregion + + + return parameters; + } //********************************************************************************** + + + getPublicKey(publicKeyInfo, signatureAlgorithm, parameters = null) { + if (parameters === null) parameters = this.fillPublicKeyParameters(publicKeyInfo, signatureAlgorithm); + const publicKeyInfoSchema = publicKeyInfo.toSchema(); + const publicKeyInfoBuffer = publicKeyInfoSchema.toBER(false); + const publicKeyInfoView = new Uint8Array(publicKeyInfoBuffer); + return this.importKey("spki", publicKeyInfoView, parameters.algorithm.algorithm, true, parameters.algorithm.usages); + } //********************************************************************************** + + + verifyWithPublicKey(data, signature, publicKeyInfo, signatureAlgorithm, shaAlgorithm = null) { + //region Initial variables + let sequence = Promise.resolve(); //endregion + //region Find signer's hashing algorithm + + if (shaAlgorithm === null) { + shaAlgorithm = this.getHashAlgorithm(signatureAlgorithm); + if (shaAlgorithm === "") return Promise.reject(`Unsupported signature algorithm: ${signatureAlgorithm.algorithmId}`); //region Import public key + + sequence = sequence.then(() => this.getPublicKey(publicKeyInfo, signatureAlgorithm)); //endregion + } else { + const parameters = {}; //region Get information about public key algorithm and default parameters for import + + let algorithmId; + if (signatureAlgorithm.algorithmId === "1.2.840.113549.1.1.10") algorithmId = signatureAlgorithm.algorithmId;else algorithmId = publicKeyInfo.algorithm.algorithmId; + const algorithmObject = this.getAlgorithmByOID(algorithmId); + if ("name" in algorithmObject === "") return Promise.reject(`Unsupported public key algorithm: ${signatureAlgorithm.algorithmId}`); + parameters.algorithm = this.getAlgorithmParameters(algorithmObject.name, "importkey"); + if ("hash" in parameters.algorithm.algorithm) parameters.algorithm.algorithm.hash.name = shaAlgorithm; //region Special case for ECDSA + + if (algorithmObject.name === "ECDSA") { + //region Get information about named curve + let algorithmParamsChecked = false; + + if ("algorithmParams" in publicKeyInfo.algorithm === true) { + if ("idBlock" in publicKeyInfo.algorithm.algorithmParams) { + if (publicKeyInfo.algorithm.algorithmParams.idBlock.tagClass === 1 && publicKeyInfo.algorithm.algorithmParams.idBlock.tagNumber === 6) algorithmParamsChecked = true; + } + } + + if (algorithmParamsChecked === false) return Promise.reject("Incorrect type for ECDSA public key parameters"); + const curveObject = this.getAlgorithmByOID(publicKeyInfo.algorithm.algorithmParams.valueBlock.toString()); + if ("name" in curveObject === false) return Promise.reject(`Unsupported named curve algorithm: ${publicKeyInfo.algorithm.algorithmParams.valueBlock.toString()}`); //endregion + + parameters.algorithm.algorithm.namedCurve = curveObject.name; + } //endregion + //endregion + //region Import public key + + + sequence = sequence.then(() => this.getPublicKey(publicKeyInfo, null, parameters)); //endregion + } //endregion + //region Verify signature + + + sequence = sequence.then(publicKey => { + //region Get default algorithm parameters for verification + const algorithm = this.getAlgorithmParameters(publicKey.algorithm.name, "verify"); + if ("hash" in algorithm.algorithm) algorithm.algorithm.hash.name = shaAlgorithm; //endregion + //region Special case for ECDSA signatures + + let signatureValue = signature.valueBlock.valueHex; + + if (publicKey.algorithm.name === "ECDSA") { + const asn1 = asn1js.fromBER(signatureValue); // noinspection JSCheckFunctionSignatures + + signatureValue = (0, _common.createECDSASignatureFromCMS)(asn1.result); + } //endregion + //region Special case for RSA-PSS + + + if (publicKey.algorithm.name === "RSA-PSS") { + let pssParameters; + + try { + pssParameters = new _RSASSAPSSParams.default({ + schema: signatureAlgorithm.algorithmParams + }); + } catch (ex) { + return Promise.reject(ex); + } + + if ("saltLength" in pssParameters) algorithm.algorithm.saltLength = pssParameters.saltLength;else algorithm.algorithm.saltLength = 20; + let hashAlgo = "SHA-1"; + + if ("hashAlgorithm" in pssParameters) { + const hashAlgorithm = this.getAlgorithmByOID(pssParameters.hashAlgorithm.algorithmId); + if ("name" in hashAlgorithm === false) return Promise.reject(`Unrecognized hash algorithm: ${pssParameters.hashAlgorithm.algorithmId}`); + hashAlgo = hashAlgorithm.name; + } + + algorithm.algorithm.hash.name = hashAlgo; + } //endregion + + + return this.verify(algorithm.algorithm, publicKey, new Uint8Array(signatureValue), new Uint8Array(data)); + }); //endregion + + return sequence; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = CryptoEngine; + +},{"./AlgorithmIdentifier.js":4,"./EncryptedContentInfo.js":34,"./PBES2Params.js":65,"./PBKDF2Params.js":66,"./PrivateKeyInfo.js":76,"./PublicKeyInfo.js":78,"./RSASSAPSSParams.js":83,"./common.js":110,"asn1js":112,"pvutils":113}],28:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _AlgorithmIdentifier = _interopRequireDefault(require("./AlgorithmIdentifier.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC3447 + */ +class DigestInfo { + //********************************************************************************** + + /** + * Constructor for DigestInfo class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {AlgorithmIdentifier} + * @desc digestAlgorithm + */ + this.digestAlgorithm = (0, _pvutils.getParametersValue)(parameters, "digestAlgorithm", DigestInfo.defaultValues("digestAlgorithm")); + /** + * @type {OctetString} + * @desc digest + */ + + this.digest = (0, _pvutils.getParametersValue)(parameters, "digest", DigestInfo.defaultValues("digest")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "digestAlgorithm": + return new _AlgorithmIdentifier.default(); + + case "digest": + return new asn1js.OctetString(); + + default: + throw new Error(`Invalid member name for DigestInfo class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + + + static compareWithDefault(memberName, memberValue) { + switch (memberName) { + case "digestAlgorithm": + return _AlgorithmIdentifier.default.compareWithDefault("algorithmId", memberValue.algorithmId) && "algorithmParams" in memberValue === false; + + case "digest": + return memberValue.isEqual(DigestInfo.defaultValues(memberName)); + + default: + throw new Error(`Invalid member name for DigestInfo class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * DigestInfo ::= SEQUENCE { + * digestAlgorithm DigestAlgorithmIdentifier, + * digest Digest } + * + * Digest ::= OCTET STRING + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [type] + * @property {string} [setName] + * @property {string} [values] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [_AlgorithmIdentifier.default.schema(names.digestAlgorithm || { + names: { + blockName: "digestAlgorithm" + } + }), new asn1js.OctetString({ + name: names.digest || "digest" + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["digestAlgorithm", "digest"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, DigestInfo.schema({ + names: { + digestAlgorithm: { + names: { + blockName: "digestAlgorithm" + } + }, + digest: "digest" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for DigestInfo"); //endregion + //region Get internal properties from parsed schema + + this.digestAlgorithm = new _AlgorithmIdentifier.default({ + schema: asn1.result.digestAlgorithm + }); + this.digest = asn1.result.digest; //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Construct and return new ASN.1 schema for this object + return new asn1js.Sequence({ + value: [this.digestAlgorithm.toSchema(), this.digest] + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + return { + digestAlgorithm: this.digestAlgorithm.toJSON(), + digest: this.digest.toJSON() + }; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = DigestInfo; + +},{"./AlgorithmIdentifier.js":4,"asn1js":112,"pvutils":113}],29:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _GeneralName = _interopRequireDefault(require("./GeneralName.js")); + +var _RelativeDistinguishedNames = _interopRequireDefault(require("./RelativeDistinguishedNames.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC5280 + */ +class DistributionPoint { + //********************************************************************************** + + /** + * Constructor for DistributionPoint class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + * @property {Object} [distributionPoint] + * @property {Object} [reasons] + * @property {Object} [cRLIssuer] + */ + constructor(parameters = {}) { + //region Internal properties of the object + if ("distributionPoint" in parameters) + /** + * @type {Array.} + * @desc distributionPoint + */ + this.distributionPoint = (0, _pvutils.getParametersValue)(parameters, "distributionPoint", DistributionPoint.defaultValues("distributionPoint")); + if ("reasons" in parameters) + /** + * @type {BitString} + * @desc values + */ + this.reasons = (0, _pvutils.getParametersValue)(parameters, "reasons", DistributionPoint.defaultValues("reasons")); + if ("cRLIssuer" in parameters) + /** + * @type {Array.} + * @desc cRLIssuer + */ + this.cRLIssuer = (0, _pvutils.getParametersValue)(parameters, "cRLIssuer", DistributionPoint.defaultValues("cRLIssuer")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "distributionPoint": + return []; + + case "reasons": + return new asn1js.BitString(); + + case "cRLIssuer": + return []; + + default: + throw new Error(`Invalid member name for DistributionPoint class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * DistributionPoint ::= SEQUENCE { + * distributionPoint [0] DistributionPointName OPTIONAL, + * reasons [1] ReasonFlags OPTIONAL, + * cRLIssuer [2] GeneralNames OPTIONAL } + * + * DistributionPointName ::= CHOICE { + * fullName [0] GeneralNames, + * nameRelativeToCRLIssuer [1] RelativeDistinguishedName } + * + * ReasonFlags ::= BIT STRING { + * unused (0), + * keyCompromise (1), + * cACompromise (2), + * affiliationChanged (3), + * superseded (4), + * cessationOfOperation (5), + * certificateHold (6), + * privilegeWithdrawn (7), + * aACompromise (8) } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [distributionPoint] + * @property {string} [distributionPointNames] + * @property {string} [reasons] + * @property {string} [cRLIssuer] + * @property {string} [cRLIssuerNames] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: [new asn1js.Choice({ + value: [new asn1js.Constructed({ + name: names.distributionPoint || "", + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: [new asn1js.Repeated({ + name: names.distributionPointNames || "", + value: _GeneralName.default.schema() + })] + }), new asn1js.Constructed({ + name: names.distributionPoint || "", + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + + }, + value: _RelativeDistinguishedNames.default.schema().valueBlock.value + })] + })] + }), new asn1js.Primitive({ + name: names.reasons || "", + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + + } + }), // IMPLICIT bitstring value + new asn1js.Constructed({ + name: names.cRLIssuer || "", + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 2 // [2] + + }, + value: [new asn1js.Repeated({ + name: names.cRLIssuerNames || "", + value: _GeneralName.default.schema() + })] + }) // IMPLICIT bitstring value + ] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["distributionPoint", "distributionPointNames", "reasons", "cRLIssuer", "cRLIssuerNames"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, DistributionPoint.schema({ + names: { + distributionPoint: "distributionPoint", + distributionPointNames: "distributionPointNames", + reasons: "reasons", + cRLIssuer: "cRLIssuer", + cRLIssuerNames: "cRLIssuerNames" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for DistributionPoint"); //endregion + //region Get internal properties from parsed schema + + if ("distributionPoint" in asn1.result) { + if (asn1.result.distributionPoint.idBlock.tagNumber === 0) // GENERAL_NAMES variant + this.distributionPoint = Array.from(asn1.result.distributionPointNames, element => new _GeneralName.default({ + schema: element + })); + + if (asn1.result.distributionPoint.idBlock.tagNumber === 1) // RDN variant + { + this.distributionPoint = new _RelativeDistinguishedNames.default({ + schema: new asn1js.Sequence({ + value: asn1.result.distributionPoint.valueBlock.value + }) + }); + } + } + + if ("reasons" in asn1.result) this.reasons = new asn1js.BitString({ + valueHex: asn1.result.reasons.valueBlock.valueHex + }); + if ("cRLIssuer" in asn1.result) this.cRLIssuer = Array.from(asn1.result.cRLIssuerNames, element => new _GeneralName.default({ + schema: element + })); //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Create array for output sequence + const outputArray = []; + + if ("distributionPoint" in this) { + let internalValue; + + if (this.distributionPoint instanceof Array) { + internalValue = new asn1js.Constructed({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: Array.from(this.distributionPoint, element => element.toSchema()) + }); + } else { + internalValue = new asn1js.Constructed({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + + }, + value: [this.distributionPoint.toSchema()] + }); + } + + outputArray.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: [internalValue] + })); + } + + if ("reasons" in this) { + outputArray.push(new asn1js.Primitive({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + + }, + valueHex: this.reasons.valueBlock.valueHex + })); + } + + if ("cRLIssuer" in this) { + outputArray.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 2 // [2] + + }, + value: Array.from(this.cRLIssuer, element => element.toSchema()) + })); + } //endregion + //region Construct and return new ASN.1 schema for this object + + + return new asn1js.Sequence({ + value: outputArray + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + const object = {}; + + if ("distributionPoint" in this) { + if (this.distributionPoint instanceof Array) object.distributionPoint = Array.from(this.distributionPoint, element => element.toJSON());else object.distributionPoint = this.distributionPoint.toJSON(); + } + + if ("reasons" in this) object.reasons = this.reasons.toJSON(); + if ("cRLIssuer" in this) object.cRLIssuer = Array.from(this.cRLIssuer, element => element.toJSON()); + return object; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = DistributionPoint; + +},{"./GeneralName.js":40,"./RelativeDistinguishedNames.js":89,"asn1js":112,"pvutils":113}],30:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _AlgorithmIdentifier = _interopRequireDefault(require("./AlgorithmIdentifier.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC6318 + */ +class ECCCMSSharedInfo { + //********************************************************************************** + + /** + * Constructor for ECCCMSSharedInfo class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {AlgorithmIdentifier} + * @desc keyInfo + */ + this.keyInfo = (0, _pvutils.getParametersValue)(parameters, "keyInfo", ECCCMSSharedInfo.defaultValues("keyInfo")); + if ("entityUInfo" in parameters) + /** + * @type {OctetString} + * @desc entityUInfo + */ + this.entityUInfo = (0, _pvutils.getParametersValue)(parameters, "entityUInfo", ECCCMSSharedInfo.defaultValues("entityUInfo")); + /** + * @type {OctetString} + * @desc suppPubInfo + */ + + this.suppPubInfo = (0, _pvutils.getParametersValue)(parameters, "suppPubInfo", ECCCMSSharedInfo.defaultValues("suppPubInfo")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "keyInfo": + return new _AlgorithmIdentifier.default(); + + case "entityUInfo": + return new asn1js.OctetString(); + + case "suppPubInfo": + return new asn1js.OctetString(); + + default: + throw new Error(`Invalid member name for ECCCMSSharedInfo class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + + + static compareWithDefault(memberName, memberValue) { + switch (memberName) { + case "keyInfo": + case "entityUInfo": + case "suppPubInfo": + return memberValue.isEqual(ECCCMSSharedInfo.defaultValues(memberName)); + + default: + throw new Error(`Invalid member name for ECCCMSSharedInfo class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * ECC-CMS-SharedInfo ::= SEQUENCE { + * keyInfo AlgorithmIdentifier, + * entityUInfo [0] EXPLICIT OCTET STRING OPTIONAL, + * suppPubInfo [2] EXPLICIT OCTET STRING } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [keyInfo] + * @property {string} [entityUInfo] + * @property {string} [suppPubInfo] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [_AlgorithmIdentifier.default.schema(names.keyInfo || {}), new asn1js.Constructed({ + name: names.entityUInfo || "", + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + optional: true, + value: [new asn1js.OctetString()] + }), new asn1js.Constructed({ + name: names.suppPubInfo || "", + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 2 // [2] + + }, + value: [new asn1js.OctetString()] + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["keyInfo", "entityUInfo", "suppPubInfo"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, ECCCMSSharedInfo.schema({ + names: { + keyInfo: { + names: { + blockName: "keyInfo" + } + }, + entityUInfo: "entityUInfo", + suppPubInfo: "suppPubInfo" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for ECCCMSSharedInfo"); //endregion + //region Get internal properties from parsed schema + + this.keyInfo = new _AlgorithmIdentifier.default({ + schema: asn1.result.keyInfo + }); + if ("entityUInfo" in asn1.result) this.entityUInfo = asn1.result.entityUInfo.valueBlock.value[0]; + this.suppPubInfo = asn1.result.suppPubInfo.valueBlock.value[0]; //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Create output array for sequence + const outputArray = []; + outputArray.push(this.keyInfo.toSchema()); + + if ("entityUInfo" in this) { + outputArray.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: [this.entityUInfo] + })); + } + + outputArray.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 2 // [2] + + }, + value: [this.suppPubInfo] + })); //endregion + //region Construct and return new ASN.1 schema for this object + + return new asn1js.Sequence({ + value: outputArray + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + const _object = { + keyInfo: this.keyInfo.toJSON() + }; + if ("entityUInfo" in this) _object.entityUInfo = this.entityUInfo.toJSON(); + _object.suppPubInfo = this.suppPubInfo.toJSON(); + return _object; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = ECCCMSSharedInfo; + +},{"./AlgorithmIdentifier.js":4,"asn1js":112,"pvutils":113}],31:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _ECPublicKey = _interopRequireDefault(require("./ECPublicKey.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC5915 + */ +class ECPrivateKey { + //********************************************************************************** + + /** + * Constructor for ECPrivateKey class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {number} + * @desc version + */ + this.version = (0, _pvutils.getParametersValue)(parameters, "version", ECPrivateKey.defaultValues("version")); + /** + * @type {OctetString} + * @desc privateKey + */ + + this.privateKey = (0, _pvutils.getParametersValue)(parameters, "privateKey", ECPrivateKey.defaultValues("privateKey")); + if ("namedCurve" in parameters) + /** + * @type {string} + * @desc namedCurve + */ + this.namedCurve = (0, _pvutils.getParametersValue)(parameters, "namedCurve", ECPrivateKey.defaultValues("namedCurve")); + if ("publicKey" in parameters) + /** + * @type {ECPublicKey} + * @desc publicKey + */ + this.publicKey = (0, _pvutils.getParametersValue)(parameters, "publicKey", ECPrivateKey.defaultValues("publicKey")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + //region If input argument array contains "json" for this object + + if ("json" in parameters) this.fromJSON(parameters.json); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "version": + return 1; + + case "privateKey": + return new asn1js.OctetString(); + + case "namedCurve": + return ""; + + case "publicKey": + return new _ECPublicKey.default(); + + default: + throw new Error(`Invalid member name for ECCPrivateKey class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + + + static compareWithDefault(memberName, memberValue) { + switch (memberName) { + case "version": + return memberValue === ECPrivateKey.defaultValues(memberName); + + case "privateKey": + return memberValue.isEqual(ECPrivateKey.defaultValues(memberName)); + + case "namedCurve": + return memberValue === ""; + + case "publicKey": + return _ECPublicKey.default.compareWithDefault("namedCurve", memberValue.namedCurve) && _ECPublicKey.default.compareWithDefault("x", memberValue.x) && _ECPublicKey.default.compareWithDefault("y", memberValue.y); + + default: + throw new Error(`Invalid member name for ECCPrivateKey class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * ECPrivateKey ::= SEQUENCE { + * version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1), + * privateKey OCTET STRING, + * parameters [0] ECParameters {{ NamedCurve }} OPTIONAL, + * publicKey [1] BIT STRING OPTIONAL + * } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [version] + * @property {string} [privateKey] + * @property {string} [namedCurve] + * @property {string} [publicKey] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [new asn1js.Integer({ + name: names.version || "" + }), new asn1js.OctetString({ + name: names.privateKey || "" + }), new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: [new asn1js.ObjectIdentifier({ + name: names.namedCurve || "" + })] + }), new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + + }, + value: [new asn1js.BitString({ + name: names.publicKey || "" + })] + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["version", "privateKey", "namedCurve", "publicKey"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, ECPrivateKey.schema({ + names: { + version: "version", + privateKey: "privateKey", + namedCurve: "namedCurve", + publicKey: "publicKey" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for ECPrivateKey"); //endregion + //region Get internal properties from parsed schema + + this.version = asn1.result.version.valueBlock.valueDec; + this.privateKey = asn1.result.privateKey; + if ("namedCurve" in asn1.result) this.namedCurve = asn1.result.namedCurve.valueBlock.toString(); + + if ("publicKey" in asn1.result) { + const publicKeyData = { + schema: asn1.result.publicKey.valueBlock.valueHex + }; + if ("namedCurve" in this) publicKeyData.namedCurve = this.namedCurve; + this.publicKey = new _ECPublicKey.default(publicKeyData); + } //endregion + + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + const outputArray = [new asn1js.Integer({ + value: this.version + }), this.privateKey]; + + if ("namedCurve" in this) { + outputArray.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: [new asn1js.ObjectIdentifier({ + value: this.namedCurve + })] + })); + } + + if ("publicKey" in this) { + outputArray.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + + }, + value: [new asn1js.BitString({ + valueHex: this.publicKey.toSchema().toBER(false) + })] + })); + } + + return new asn1js.Sequence({ + value: outputArray + }); + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + if ("namedCurve" in this === false || ECPrivateKey.compareWithDefault("namedCurve", this.namedCurve)) throw new Error("Not enough information for making JSON: absent \"namedCurve\" value"); + let crvName = ""; + + switch (this.namedCurve) { + case "1.2.840.10045.3.1.7": + // P-256 + crvName = "P-256"; + break; + + case "1.3.132.0.34": + // P-384 + crvName = "P-384"; + break; + + case "1.3.132.0.35": + // P-521 + crvName = "P-521"; + break; + + default: + } + + const privateKeyJSON = { + crv: crvName, + d: (0, _pvutils.toBase64)((0, _pvutils.arrayBufferToString)(this.privateKey.valueBlock.valueHex), true, true, false) + }; + + if ("publicKey" in this) { + const publicKeyJSON = this.publicKey.toJSON(); + privateKeyJSON.x = publicKeyJSON.x; + privateKeyJSON.y = publicKeyJSON.y; + } + + return privateKeyJSON; + } //********************************************************************************** + + /** + * Convert JSON value into current object + * @param {Object} json + */ + + + fromJSON(json) { + let coodinateLength = 0; + + if ("crv" in json) { + switch (json.crv.toUpperCase()) { + case "P-256": + this.namedCurve = "1.2.840.10045.3.1.7"; + coodinateLength = 32; + break; + + case "P-384": + this.namedCurve = "1.3.132.0.34"; + coodinateLength = 48; + break; + + case "P-521": + this.namedCurve = "1.3.132.0.35"; + coodinateLength = 66; + break; + + default: + } + } else throw new Error("Absent mandatory parameter \"crv\""); + + if ("d" in json) { + const convertBuffer = (0, _pvutils.stringToArrayBuffer)((0, _pvutils.fromBase64)(json.d, true)); + + if (convertBuffer.byteLength < coodinateLength) { + const buffer = new ArrayBuffer(coodinateLength); + const view = new Uint8Array(buffer); + const convertBufferView = new Uint8Array(convertBuffer); + view.set(convertBufferView, 1); + this.privateKey = new asn1js.OctetString({ + valueHex: buffer + }); + } else this.privateKey = new asn1js.OctetString({ + valueHex: convertBuffer.slice(0, coodinateLength) + }); + } else throw new Error("Absent mandatory parameter \"d\""); + + if ("x" in json && "y" in json) this.publicKey = new _ECPublicKey.default({ + json + }); + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = ECPrivateKey; + +},{"./ECPublicKey.js":32,"asn1js":112,"pvutils":113}],32:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC5480 + */ +class ECPublicKey { + //********************************************************************************** + + /** + * Constructor for ECCPublicKey class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {ArrayBuffer} + * @desc type + */ + this.x = (0, _pvutils.getParametersValue)(parameters, "x", ECPublicKey.defaultValues("x")); + /** + * @type {ArrayBuffer} + * @desc values + */ + + this.y = (0, _pvutils.getParametersValue)(parameters, "y", ECPublicKey.defaultValues("y")); + /** + * @type {string} + * @desc namedCurve + */ + + this.namedCurve = (0, _pvutils.getParametersValue)(parameters, "namedCurve", ECPublicKey.defaultValues("namedCurve")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + //region If input argument array contains "json" for this object + + if ("json" in parameters) this.fromJSON(parameters.json); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "x": + case "y": + return new ArrayBuffer(0); + + case "namedCurve": + return ""; + + default: + throw new Error(`Invalid member name for ECCPublicKey class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + + + static compareWithDefault(memberName, memberValue) { + switch (memberName) { + case "x": + case "y": + return (0, _pvutils.isEqualBuffer)(memberValue, ECPublicKey.defaultValues(memberName)); + + case "namedCurve": + return memberValue === ""; + + default: + throw new Error(`Invalid member name for ECCPublicKey class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + return new asn1js.RawData(); + } //********************************************************************************** + + /** + * Convert ArrayBuffer into current class + * @param {!ArrayBuffer} schema Special case: schema is an ArrayBuffer + */ + + + fromSchema(schema) { + //region Check the schema is valid + if (schema instanceof ArrayBuffer === false) throw new Error("Object's schema was not verified against input data for ECPublicKey"); + const view = new Uint8Array(schema); + if (view[0] !== 0x04) throw new Error("Object's schema was not verified against input data for ECPublicKey"); //endregion + //region Get internal properties from parsed schema + + let coordinateLength; + + switch (this.namedCurve) { + case "1.2.840.10045.3.1.7": + // P-256 + coordinateLength = 32; + break; + + case "1.3.132.0.34": + // P-384 + coordinateLength = 48; + break; + + case "1.3.132.0.35": + // P-521 + coordinateLength = 66; + break; + + default: + throw new Error(`Incorrect curve OID: ${this.namedCurve}`); + } + + if (schema.byteLength !== coordinateLength * 2 + 1) throw new Error("Object's schema was not verified against input data for ECPublicKey"); + this.x = schema.slice(1, coordinateLength + 1); + this.y = schema.slice(1 + coordinateLength, coordinateLength * 2 + 1); //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + return new asn1js.RawData({ + data: (0, _pvutils.utilConcatBuf)(new Uint8Array([0x04]).buffer, this.x, this.y) + }); + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + let crvName = ""; + + switch (this.namedCurve) { + case "1.2.840.10045.3.1.7": + // P-256 + crvName = "P-256"; + break; + + case "1.3.132.0.34": + // P-384 + crvName = "P-384"; + break; + + case "1.3.132.0.35": + // P-521 + crvName = "P-521"; + break; + + default: + } + + return { + crv: crvName, + x: (0, _pvutils.toBase64)((0, _pvutils.arrayBufferToString)(this.x), true, true, false), + y: (0, _pvutils.toBase64)((0, _pvutils.arrayBufferToString)(this.y), true, true, false) + }; + } //********************************************************************************** + + /** + * Convert JSON value into current object + * @param {Object} json + */ + + + fromJSON(json) { + let coodinateLength = 0; + + if ("crv" in json) { + switch (json.crv.toUpperCase()) { + case "P-256": + this.namedCurve = "1.2.840.10045.3.1.7"; + coodinateLength = 32; + break; + + case "P-384": + this.namedCurve = "1.3.132.0.34"; + coodinateLength = 48; + break; + + case "P-521": + this.namedCurve = "1.3.132.0.35"; + coodinateLength = 66; + break; + + default: + } + } else throw new Error("Absent mandatory parameter \"crv\""); + + if ("x" in json) { + const convertBuffer = (0, _pvutils.stringToArrayBuffer)((0, _pvutils.fromBase64)(json.x, true)); + + if (convertBuffer.byteLength < coodinateLength) { + this.x = new ArrayBuffer(coodinateLength); + const view = new Uint8Array(this.x); + const convertBufferView = new Uint8Array(convertBuffer); + view.set(convertBufferView, 1); + } else this.x = convertBuffer.slice(0, coodinateLength); + } else throw new Error("Absent mandatory parameter \"x\""); + + if ("y" in json) { + const convertBuffer = (0, _pvutils.stringToArrayBuffer)((0, _pvutils.fromBase64)(json.y, true)); + + if (convertBuffer.byteLength < coodinateLength) { + this.y = new ArrayBuffer(coodinateLength); + const view = new Uint8Array(this.y); + const convertBufferView = new Uint8Array(convertBuffer); + view.set(convertBufferView, 1); + } else this.y = convertBuffer.slice(0, coodinateLength); + } else throw new Error("Absent mandatory parameter \"y\""); + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = ECPublicKey; + +},{"asn1js":112,"pvutils":113}],33:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC5652 + */ +class EncapsulatedContentInfo { + //********************************************************************************** + + /** + * Constructor for EncapsulatedContentInfo class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {string} + * @desc eContentType + */ + this.eContentType = (0, _pvutils.getParametersValue)(parameters, "eContentType", EncapsulatedContentInfo.defaultValues("eContentType")); + + if ("eContent" in parameters) { + /** + * @type {OctetString} + * @desc eContent + */ + this.eContent = (0, _pvutils.getParametersValue)(parameters, "eContent", EncapsulatedContentInfo.defaultValues("eContent")); + + if (this.eContent.idBlock.tagClass === 1 && this.eContent.idBlock.tagNumber === 4) { + //region Divide OCTETSTRING value down to small pieces + if (this.eContent.idBlock.isConstructed === false) { + const constrString = new asn1js.OctetString({ + idBlock: { + isConstructed: true + }, + isConstructed: true + }); + let offset = 0; + let length = this.eContent.valueBlock.valueHex.byteLength; + + while (length > 0) { + const pieceView = new Uint8Array(this.eContent.valueBlock.valueHex, offset, offset + 65536 > this.eContent.valueBlock.valueHex.byteLength ? this.eContent.valueBlock.valueHex.byteLength - offset : 65536); + + const _array = new ArrayBuffer(pieceView.length); + + const _view = new Uint8Array(_array); + + for (let i = 0; i < _view.length; i++) _view[i] = pieceView[i]; + + constrString.valueBlock.value.push(new asn1js.OctetString({ + valueHex: _array + })); + length -= pieceView.length; + offset += pieceView.length; + } + + this.eContent = constrString; + } //endregion + + } + } //endregion + //region If input argument array contains "schema" for this object + + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "eContentType": + return ""; + + case "eContent": + return new asn1js.OctetString(); + + default: + throw new Error(`Invalid member name for EncapsulatedContentInfo class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + + + static compareWithDefault(memberName, memberValue) { + switch (memberName) { + case "eContentType": + return memberValue === ""; + + case "eContent": + { + if (memberValue.idBlock.tagClass === 1 && memberValue.idBlock.tagNumber === 4) return memberValue.isEqual(EncapsulatedContentInfo.defaultValues("eContent")); + return false; + } + + default: + throw new Error(`Invalid member name for EncapsulatedContentInfo class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * EncapsulatedContentInfo ::= SEQUENCE { + * eContentType ContentType, + * eContent [0] EXPLICIT OCTET STRING OPTIONAL } * Changed it to ANY, as in PKCS#7 + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [type] + * @property {string} [setName] + * @property {string} [values] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [new asn1js.ObjectIdentifier({ + name: names.eContentType || "" + }), new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: [new asn1js.Any({ + name: names.eContent || "" + }) // In order to aling this with PKCS#7 and CMS as well + ] + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["eContentType", "eContent"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, EncapsulatedContentInfo.schema({ + names: { + eContentType: "eContentType", + eContent: "eContent" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for EncapsulatedContentInfo"); //endregion + //region Get internal properties from parsed schema + + this.eContentType = asn1.result.eContentType.valueBlock.toString(); + if ("eContent" in asn1.result) this.eContent = asn1.result.eContent; //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Create array for output sequence + const outputArray = []; + outputArray.push(new asn1js.ObjectIdentifier({ + value: this.eContentType + })); + + if ("eContent" in this) { + if (EncapsulatedContentInfo.compareWithDefault("eContent", this.eContent) === false) { + outputArray.push(new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: [this.eContent] + })); + } + } //endregion + //region Construct and return new ASN.1 schema for this object + + + return new asn1js.Sequence({ + value: outputArray + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + const _object = { + eContentType: this.eContentType + }; + + if ("eContent" in this) { + if (EncapsulatedContentInfo.compareWithDefault("eContent", this.eContent) === false) _object.eContent = this.eContent.toJSON(); + } + + return _object; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = EncapsulatedContentInfo; + +},{"asn1js":112,"pvutils":113}],34:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _AlgorithmIdentifier = _interopRequireDefault(require("./AlgorithmIdentifier.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC5652 + */ +class EncryptedContentInfo { + //********************************************************************************** + + /** + * Constructor for EncryptedContentInfo class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {string} + * @desc contentType + */ + this.contentType = (0, _pvutils.getParametersValue)(parameters, "contentType", EncryptedContentInfo.defaultValues("contentType")); + /** + * @type {AlgorithmIdentifier} + * @desc contentEncryptionAlgorithm + */ + + this.contentEncryptionAlgorithm = (0, _pvutils.getParametersValue)(parameters, "contentEncryptionAlgorithm", EncryptedContentInfo.defaultValues("contentEncryptionAlgorithm")); + + if ("encryptedContent" in parameters) { + /** + * @type {OctetString} + * @desc encryptedContent (!!!) could be contructive or primitive value (!!!) + */ + this.encryptedContent = parameters.encryptedContent; + + if (this.encryptedContent.idBlock.tagClass === 1 && this.encryptedContent.idBlock.tagNumber === 4) { + //region Divide OCTETSTRING value down to small pieces + if (this.encryptedContent.idBlock.isConstructed === false) { + const constrString = new asn1js.OctetString({ + idBlock: { + isConstructed: true + }, + isConstructed: true + }); + let offset = 0; + let length = this.encryptedContent.valueBlock.valueHex.byteLength; + + while (length > 0) { + const pieceView = new Uint8Array(this.encryptedContent.valueBlock.valueHex, offset, offset + 1024 > this.encryptedContent.valueBlock.valueHex.byteLength ? this.encryptedContent.valueBlock.valueHex.byteLength - offset : 1024); + + const _array = new ArrayBuffer(pieceView.length); + + const _view = new Uint8Array(_array); + + for (let i = 0; i < _view.length; i++) _view[i] = pieceView[i]; + + constrString.valueBlock.value.push(new asn1js.OctetString({ + valueHex: _array + })); + length -= pieceView.length; + offset += pieceView.length; + } + + this.encryptedContent = constrString; + } //endregion + + } + } //endregion + //region If input argument array contains "schema" for this object + + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "contentType": + return ""; + + case "contentEncryptionAlgorithm": + return new _AlgorithmIdentifier.default(); + + case "encryptedContent": + return new asn1js.OctetString(); + + default: + throw new Error(`Invalid member name for EncryptedContentInfo class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + + + static compareWithDefault(memberName, memberValue) { + switch (memberName) { + case "contentType": + return memberValue === ""; + + case "contentEncryptionAlgorithm": + return memberValue.algorithmId === "" && "algorithmParams" in memberValue === false; + + case "encryptedContent": + return memberValue.isEqual(EncryptedContentInfo.defaultValues(memberName)); + + default: + throw new Error(`Invalid member name for EncryptedContentInfo class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * EncryptedContentInfo ::= SEQUENCE { + * contentType ContentType, + * contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier, + * encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL } + * + * Comment: Strange, but modern crypto engines create "encryptedContent" as "[0] EXPLICIT EncryptedContent" + * + * EncryptedContent ::= OCTET STRING + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [contentType] + * @property {string} [contentEncryptionAlgorithm] + * @property {string} [encryptedContent] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [new asn1js.ObjectIdentifier({ + name: names.contentType || "" + }), _AlgorithmIdentifier.default.schema(names.contentEncryptionAlgorithm || {}), // The CHOICE we need because "EncryptedContent" could have either "constructive" + // or "primitive" form of encoding and we need to handle both variants + new asn1js.Choice({ + value: [new asn1js.Constructed({ + name: names.encryptedContent || "", + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: [new asn1js.Repeated({ + value: new asn1js.OctetString() + })] + }), new asn1js.Primitive({ + name: names.encryptedContent || "", + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + } + })] + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["contentType", "contentEncryptionAlgorithm", "encryptedContent"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, EncryptedContentInfo.schema({ + names: { + contentType: "contentType", + contentEncryptionAlgorithm: { + names: { + blockName: "contentEncryptionAlgorithm" + } + }, + encryptedContent: "encryptedContent" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for EncryptedContentInfo"); //endregion + //region Get internal properties from parsed schema + + this.contentType = asn1.result.contentType.valueBlock.toString(); + this.contentEncryptionAlgorithm = new _AlgorithmIdentifier.default({ + schema: asn1.result.contentEncryptionAlgorithm + }); + + if ("encryptedContent" in asn1.result) { + this.encryptedContent = asn1.result.encryptedContent; + this.encryptedContent.idBlock.tagClass = 1; // UNIVERSAL + + this.encryptedContent.idBlock.tagNumber = 4; // OCTETSTRING (!!!) The value still has instance of "in_window.org.pkijs.asn1.ASN1_CONSTRUCTED / ASN1_PRIMITIVE" + } //endregion + + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Create array for output sequence + const sequenceLengthBlock = { + isIndefiniteForm: false + }; + const outputArray = []; + outputArray.push(new asn1js.ObjectIdentifier({ + value: this.contentType + })); + outputArray.push(this.contentEncryptionAlgorithm.toSchema()); + + if ("encryptedContent" in this) { + sequenceLengthBlock.isIndefiniteForm = this.encryptedContent.idBlock.isConstructed; + const encryptedValue = this.encryptedContent; + encryptedValue.idBlock.tagClass = 3; // CONTEXT-SPECIFIC + + encryptedValue.idBlock.tagNumber = 0; // [0] + + encryptedValue.lenBlock.isIndefiniteForm = this.encryptedContent.idBlock.isConstructed; + outputArray.push(encryptedValue); + } //endregion + //region Construct and return new ASN.1 schema for this object + + + return new asn1js.Sequence({ + lenBlock: sequenceLengthBlock, + value: outputArray + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + const _object = { + contentType: this.contentType, + contentEncryptionAlgorithm: this.contentEncryptionAlgorithm.toJSON() + }; + if ("encryptedContent" in this) _object.encryptedContent = this.encryptedContent.toJSON(); + return _object; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = EncryptedContentInfo; + +},{"./AlgorithmIdentifier.js":4,"asn1js":112,"pvutils":113}],35:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _common = require("./common.js"); + +var _EncryptedContentInfo = _interopRequireDefault(require("./EncryptedContentInfo.js")); + +var _Attribute = _interopRequireDefault(require("./Attribute.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC5652 + */ +class EncryptedData { + //********************************************************************************** + + /** + * Constructor for EncryptedData class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {number} + * @desc version + */ + this.version = (0, _pvutils.getParametersValue)(parameters, "version", EncryptedData.defaultValues("version")); + /** + * @type {EncryptedContentInfo} + * @desc encryptedContentInfo + */ + + this.encryptedContentInfo = (0, _pvutils.getParametersValue)(parameters, "encryptedContentInfo", EncryptedData.defaultValues("encryptedContentInfo")); + if ("unprotectedAttrs" in parameters) + /** + * @type {Array.} + * @desc unprotectedAttrs + */ + this.unprotectedAttrs = (0, _pvutils.getParametersValue)(parameters, "unprotectedAttrs", EncryptedData.defaultValues("unprotectedAttrs")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "version": + return 0; + + case "encryptedContentInfo": + return new _EncryptedContentInfo.default(); + + case "unprotectedAttrs": + return []; + + default: + throw new Error(`Invalid member name for EncryptedData class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + + + static compareWithDefault(memberName, memberValue) { + switch (memberName) { + case "version": + return memberValue === 0; + + case "encryptedContentInfo": + return _EncryptedContentInfo.default.compareWithDefault("contentType", memberValue.contentType) && _EncryptedContentInfo.default.compareWithDefault("contentEncryptionAlgorithm", memberValue.contentEncryptionAlgorithm) && _EncryptedContentInfo.default.compareWithDefault("encryptedContent", memberValue.encryptedContent); + + case "unprotectedAttrs": + return memberValue.length === 0; + + default: + throw new Error(`Invalid member name for EncryptedData class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * EncryptedData ::= SEQUENCE { + * version CMSVersion, + * encryptedContentInfo EncryptedContentInfo, + * unprotectedAttrs [1] IMPLICIT UnprotectedAttributes OPTIONAL } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [version] + * @property {string} [encryptedContentInfo] + * @property {string} [unprotectedAttrs] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [new asn1js.Integer({ + name: names.version || "" + }), _EncryptedContentInfo.default.schema(names.encryptedContentInfo || {}), new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + + }, + value: [new asn1js.Repeated({ + name: names.unprotectedAttrs || "", + value: _Attribute.default.schema() + })] + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["version", "encryptedContentInfo", "unprotectedAttrs"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, EncryptedData.schema({ + names: { + version: "version", + encryptedContentInfo: { + names: { + blockName: "encryptedContentInfo" + } + }, + unprotectedAttrs: "unprotectedAttrs" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for EncryptedData"); //endregion + //region Get internal properties from parsed schema + + this.version = asn1.result.version.valueBlock.valueDec; + this.encryptedContentInfo = new _EncryptedContentInfo.default({ + schema: asn1.result.encryptedContentInfo + }); + if ("unprotectedAttrs" in asn1.result) this.unprotectedAttrs = Array.from(asn1.result.unprotectedAttrs, element => new _Attribute.default({ + schema: element + })); //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Create array for output sequence + const outputArray = []; + outputArray.push(new asn1js.Integer({ + value: this.version + })); + outputArray.push(this.encryptedContentInfo.toSchema()); + + if ("unprotectedAttrs" in this) { + outputArray.push(new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + + }, + value: Array.from(this.unprotectedAttrs, element => element.toSchema()) + })); + } //endregion + //region Construct and return new ASN.1 schema for this object + + + return new asn1js.Sequence({ + value: outputArray + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + const _object = { + version: this.version, + encryptedContentInfo: this.encryptedContentInfo.toJSON() + }; + if ("unprotectedAttrs" in this) _object.unprotectedAttrs = Array.from(this.unprotectedAttrs, element => element.toJSON()); + return _object; + } //********************************************************************************** + + /** + * Create a new CMS Encrypted Data content + * @param {Object} parameters Parameters neccessary for encryption + * @returns {Promise} + */ + + + encrypt(parameters) { + //region Check for input parameters + if (parameters instanceof Object === false) return Promise.reject("Parameters must have type \"Object\""); //endregion + //region Get cryptographic engine + + const engine = (0, _common.getEngine)(); + if (typeof engine === "undefined") return Promise.reject("Unable to initialize cryptographic engine"); //endregion + //region Set "contentType" parameter + + parameters.contentType = "1.2.840.113549.1.7.1"; // "data" + //endregion + + if ("encryptEncryptedContentInfo" in engine.subtle) { + return engine.subtle.encryptEncryptedContentInfo(parameters).then(result => { + this.encryptedContentInfo = result; + }); + } + + return Promise.reject(`No support for "encryptEncryptedContentInfo" in current crypto engine ${engine.name}`); + } //********************************************************************************** + + /** + * Create a new CMS Encrypted Data content + * @param {Object} parameters Parameters neccessary for encryption + */ + + + decrypt(parameters) { + //region Check for input parameters + if (parameters instanceof Object === false) return Promise.reject("Parameters must have type \"Object\""); //endregion + //region Get cryptographic engine + + const engine = (0, _common.getEngine)(); + if (typeof engine === "undefined") return Promise.reject("Unable to initialize cryptographic engine"); //endregion + //region Set "encryptedContentInfo" value + + parameters.encryptedContentInfo = this.encryptedContentInfo; //endregion + + if ("decryptEncryptedContentInfo" in engine.subtle) return engine.subtle.decryptEncryptedContentInfo(parameters); + return Promise.reject(`No support for "decryptEncryptedContentInfo" in current crypto engine ${engine.name}`); + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = EncryptedData; + +},{"./Attribute.js":6,"./EncryptedContentInfo.js":34,"./common.js":110,"asn1js":112,"pvutils":113}],36:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _common = require("./common.js"); + +var _OriginatorInfo = _interopRequireDefault(require("./OriginatorInfo.js")); + +var _RecipientInfo = _interopRequireDefault(require("./RecipientInfo.js")); + +var _EncryptedContentInfo = _interopRequireDefault(require("./EncryptedContentInfo.js")); + +var _Attribute = _interopRequireDefault(require("./Attribute.js")); + +var _AlgorithmIdentifier = _interopRequireDefault(require("./AlgorithmIdentifier.js")); + +var _RSAESOAEPParams = _interopRequireDefault(require("./RSAESOAEPParams.js")); + +var _KeyTransRecipientInfo = _interopRequireDefault(require("./KeyTransRecipientInfo.js")); + +var _IssuerAndSerialNumber = _interopRequireDefault(require("./IssuerAndSerialNumber.js")); + +var _RecipientEncryptedKey = _interopRequireDefault(require("./RecipientEncryptedKey.js")); + +var _KeyAgreeRecipientIdentifier = _interopRequireDefault(require("./KeyAgreeRecipientIdentifier.js")); + +var _KeyAgreeRecipientInfo = _interopRequireDefault(require("./KeyAgreeRecipientInfo.js")); + +var _RecipientEncryptedKeys = _interopRequireDefault(require("./RecipientEncryptedKeys.js")); + +var _KEKRecipientInfo = _interopRequireDefault(require("./KEKRecipientInfo.js")); + +var _KEKIdentifier = _interopRequireDefault(require("./KEKIdentifier.js")); + +var _PBKDF2Params = _interopRequireDefault(require("./PBKDF2Params.js")); + +var _PasswordRecipientinfo = _interopRequireDefault(require("./PasswordRecipientinfo.js")); + +var _ECCCMSSharedInfo = _interopRequireDefault(require("./ECCCMSSharedInfo.js")); + +var _OriginatorIdentifierOrKey = _interopRequireDefault(require("./OriginatorIdentifierOrKey.js")); + +var _OriginatorPublicKey = _interopRequireDefault(require("./OriginatorPublicKey.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC5652 + */ +class EnvelopedData { + //********************************************************************************** + + /** + * Constructor for EnvelopedData class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {number} + * @desc version + */ + this.version = (0, _pvutils.getParametersValue)(parameters, "version", EnvelopedData.defaultValues("version")); + if ("originatorInfo" in parameters) + /** + * @type {OriginatorInfo} + * @desc originatorInfo + */ + this.originatorInfo = (0, _pvutils.getParametersValue)(parameters, "originatorInfo", EnvelopedData.defaultValues("originatorInfo")); + /** + * @type {Array.} + * @desc recipientInfos + */ + + this.recipientInfos = (0, _pvutils.getParametersValue)(parameters, "recipientInfos", EnvelopedData.defaultValues("recipientInfos")); + /** + * @type {EncryptedContentInfo} + * @desc encryptedContentInfo + */ + + this.encryptedContentInfo = (0, _pvutils.getParametersValue)(parameters, "encryptedContentInfo", EnvelopedData.defaultValues("encryptedContentInfo")); + if ("unprotectedAttrs" in parameters) + /** + * @type {Array.} + * @desc unprotectedAttrs + */ + this.unprotectedAttrs = (0, _pvutils.getParametersValue)(parameters, "unprotectedAttrs", EnvelopedData.defaultValues("unprotectedAttrs")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "version": + return 0; + + case "originatorInfo": + return new _OriginatorInfo.default(); + + case "recipientInfos": + return []; + + case "encryptedContentInfo": + return new _EncryptedContentInfo.default(); + + case "unprotectedAttrs": + return []; + + default: + throw new Error(`Invalid member name for EnvelopedData class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + + + static compareWithDefault(memberName, memberValue) { + switch (memberName) { + case "version": + return memberValue === EnvelopedData.defaultValues(memberName); + + case "originatorInfo": + return memberValue.certs.certificates.length === 0 && memberValue.crls.crls.length === 0; + + case "recipientInfos": + case "unprotectedAttrs": + return memberValue.length === 0; + + case "encryptedContentInfo": + return _EncryptedContentInfo.default.compareWithDefault("contentType", memberValue.contentType) && _EncryptedContentInfo.default.compareWithDefault("contentEncryptionAlgorithm", memberValue.contentEncryptionAlgorithm) && _EncryptedContentInfo.default.compareWithDefault("encryptedContent", memberValue.encryptedContent); + + default: + throw new Error(`Invalid member name for EnvelopedData class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * EnvelopedData ::= SEQUENCE { + * version CMSVersion, + * originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL, + * recipientInfos RecipientInfos, + * encryptedContentInfo EncryptedContentInfo, + * unprotectedAttrs [1] IMPLICIT UnprotectedAttributes OPTIONAL } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [version] + * @property {string} [originatorInfo] + * @property {string} [recipientInfos] + * @property {string} [encryptedContentInfo] + * @property {string} [unprotectedAttrs] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [new asn1js.Integer({ + name: names.version || "" + }), new asn1js.Constructed({ + name: names.originatorInfo || "", + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: _OriginatorInfo.default.schema().valueBlock.value + }), new asn1js.Set({ + value: [new asn1js.Repeated({ + name: names.recipientInfos || "", + value: _RecipientInfo.default.schema() + })] + }), _EncryptedContentInfo.default.schema(names.encryptedContentInfo || {}), new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + + }, + value: [new asn1js.Repeated({ + name: names.unprotectedAttrs || "", + value: _Attribute.default.schema() + })] + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["version", "originatorInfo", "recipientInfos", "encryptedContentInfo", "unprotectedAttrs"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, EnvelopedData.schema({ + names: { + version: "version", + originatorInfo: "originatorInfo", + recipientInfos: "recipientInfos", + encryptedContentInfo: { + names: { + blockName: "encryptedContentInfo" + } + }, + unprotectedAttrs: "unprotectedAttrs" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for EnvelopedData"); //endregion + //region Get internal properties from parsed schema + + this.version = asn1.result.version.valueBlock.valueDec; + + if ("originatorInfo" in asn1.result) { + this.originatorInfo = new _OriginatorInfo.default({ + schema: new asn1js.Sequence({ + value: asn1.result.originatorInfo.valueBlock.value + }) + }); + } + + this.recipientInfos = Array.from(asn1.result.recipientInfos, element => new _RecipientInfo.default({ + schema: element + })); + this.encryptedContentInfo = new _EncryptedContentInfo.default({ + schema: asn1.result.encryptedContentInfo + }); + if ("unprotectedAttrs" in asn1.result) this.unprotectedAttrs = Array.from(asn1.result.unprotectedAttrs, element => new _Attribute.default({ + schema: element + })); //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Create array for output sequence + const outputArray = []; + outputArray.push(new asn1js.Integer({ + value: this.version + })); + + if ("originatorInfo" in this) { + outputArray.push(new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: this.originatorInfo.toSchema().valueBlock.value + })); + } + + outputArray.push(new asn1js.Set({ + value: Array.from(this.recipientInfos, element => element.toSchema()) + })); + outputArray.push(this.encryptedContentInfo.toSchema()); + + if ("unprotectedAttrs" in this) { + outputArray.push(new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + + }, + value: Array.from(this.unprotectedAttrs, element => element.toSchema()) + })); + } //endregion + //region Construct and return new ASN.1 schema for this object + + + return new asn1js.Sequence({ + value: outputArray + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + const _object = { + version: this.version + }; + if ("originatorInfo" in this) _object.originatorInfo = this.originatorInfo.toJSON(); + _object.recipientInfos = Array.from(this.recipientInfos, element => element.toJSON()); + _object.encryptedContentInfo = this.encryptedContentInfo.toJSON(); + if ("unprotectedAttrs" in this) _object.unprotectedAttrs = Array.from(this.unprotectedAttrs, element => element.toJSON()); + return _object; + } //********************************************************************************** + + /** + * Helpers function for filling "RecipientInfo" based on recipient's certificate. + * Problem with WebCrypto is that for RSA certificates we have only one option - "key transport" and + * for ECC certificates we also have one option - "key agreement". As soon as Google will implement + * DH algorithm it would be possible to use "key agreement" also for RSA certificates. + * @param {Certificate} [certificate] Recipient's certificate + * @param {Object} [parameters] Additional parameters neccessary for "fine tunning" of encryption process + * @param {number} [variant] Variant = 1 is for "key transport", variant = 2 is for "key agreement". In fact the "variant" is unneccessary now because Google has no DH algorithm implementation. Thus key encryption scheme would be choosen by certificate type only: "key transport" for RSA and "key agreement" for ECC certificates. + */ + + + addRecipientByCertificate(certificate, parameters, variant) { + //region Initial variables + const encryptionParameters = parameters || {}; //endregion + //region Check type of certificate + + if (certificate.subjectPublicKeyInfo.algorithm.algorithmId.indexOf("1.2.840.113549") !== -1) variant = 1; // For the moment it is the only variant for RSA-based certificates + else { + if (certificate.subjectPublicKeyInfo.algorithm.algorithmId.indexOf("1.2.840.10045") !== -1) variant = 2; // For the moment it is the only variant for ECC-based certificates + else throw new Error(`Unknown type of certificate's public key: ${certificate.subjectPublicKeyInfo.algorithm.algorithmId}`); + } //endregion + //region Initialize encryption parameters + + if ("oaepHashAlgorithm" in encryptionParameters === false) encryptionParameters.oaepHashAlgorithm = "SHA-512"; + if ("kdfAlgorithm" in encryptionParameters === false) encryptionParameters.kdfAlgorithm = "SHA-512"; + if ("kekEncryptionLength" in encryptionParameters === false) encryptionParameters.kekEncryptionLength = 256; //endregion + //region Add new "recipient" depends on "variant" and certificate type + + switch (variant) { + case 1: + // Key transport scheme + { + //region keyEncryptionAlgorithm + const oaepOID = (0, _common.getOIDByAlgorithm)({ + name: "RSA-OAEP" + }); + if (oaepOID === "") throw new Error("Can not find OID for OAEP"); //endregion + //region RSAES-OAEP-params + + const hashOID = (0, _common.getOIDByAlgorithm)({ + name: encryptionParameters.oaepHashAlgorithm + }); + if (hashOID === "") throw new Error(`Unknown OAEP hash algorithm: ${encryptionParameters.oaepHashAlgorithm}`); + const hashAlgorithm = new _AlgorithmIdentifier.default({ + algorithmId: hashOID, + algorithmParams: new asn1js.Null() + }); + const rsaOAEPParams = new _RSAESOAEPParams.default({ + hashAlgorithm, + maskGenAlgorithm: new _AlgorithmIdentifier.default({ + algorithmId: "1.2.840.113549.1.1.8", + // id-mgf1 + algorithmParams: hashAlgorithm.toSchema() + }) + }); //endregion + //region KeyTransRecipientInfo + + const keyInfo = new _KeyTransRecipientInfo.default({ + version: 0, + rid: new _IssuerAndSerialNumber.default({ + issuer: certificate.issuer, + serialNumber: certificate.serialNumber + }), + keyEncryptionAlgorithm: new _AlgorithmIdentifier.default({ + algorithmId: oaepOID, + algorithmParams: rsaOAEPParams.toSchema() + }), + recipientCertificate: certificate // "encryptedKey" will be calculated in "encrypt" function + + }); //endregion + //region Final values for "CMS_ENVELOPED_DATA" + + this.recipientInfos.push(new _RecipientInfo.default({ + variant: 1, + value: keyInfo + })); //endregion + } + break; + + case 2: + // Key agreement scheme + { + //region RecipientEncryptedKey + const encryptedKey = new _RecipientEncryptedKey.default({ + rid: new _KeyAgreeRecipientIdentifier.default({ + variant: 1, + value: new _IssuerAndSerialNumber.default({ + issuer: certificate.issuer, + serialNumber: certificate.serialNumber + }) + }) // "encryptedKey" will be calculated in "encrypt" function + + }); //endregion + //region keyEncryptionAlgorithm + + const aesKWoid = (0, _common.getOIDByAlgorithm)({ + name: "AES-KW", + length: encryptionParameters.kekEncryptionLength + }); + if (aesKWoid === "") throw new Error(`Unknown length for key encryption algorithm: ${encryptionParameters.kekEncryptionLength}`); + const aesKW = new _AlgorithmIdentifier.default({ + algorithmId: aesKWoid, + algorithmParams: new asn1js.Null() + }); //endregion + //region KeyAgreeRecipientInfo + + const ecdhOID = (0, _common.getOIDByAlgorithm)({ + name: "ECDH", + kdf: encryptionParameters.kdfAlgorithm + }); + if (ecdhOID === "") throw new Error(`Unknown KDF algorithm: ${encryptionParameters.kdfAlgorithm}`); // In fact there is no need in so long UKM, but RFC2631 + // has requirement that "UserKeyMaterial" must be 512 bits long + + const ukmBuffer = new ArrayBuffer(64); + const ukmView = new Uint8Array(ukmBuffer); + (0, _common.getRandomValues)(ukmView); // Generate random values in 64 bytes long buffer + + const keyInfo = new _KeyAgreeRecipientInfo.default({ + version: 3, + // "originator" will be calculated in "encrypt" function because ephemeral key would be generated there + ukm: new asn1js.OctetString({ + valueHex: ukmBuffer + }), + keyEncryptionAlgorithm: new _AlgorithmIdentifier.default({ + algorithmId: ecdhOID, + algorithmParams: aesKW.toSchema() + }), + recipientEncryptedKeys: new _RecipientEncryptedKeys.default({ + encryptedKeys: [encryptedKey] + }), + recipientCertificate: certificate + }); //endregion + //region Final values for "CMS_ENVELOPED_DATA" + + this.recipientInfos.push(new _RecipientInfo.default({ + variant: 2, + value: keyInfo + })); //endregion + } + break; + + default: + throw new Error(`Unknown "variant" value: ${variant}`); + } //endregion + + + return true; + } //********************************************************************************** + + /** + * Add recipient based on pre-defined data like password or KEK + * @param {ArrayBuffer} preDefinedData ArrayBuffer with pre-defined data + * @param {Object} parameters Additional parameters neccessary for "fine tunning" of encryption process + * @param {number} variant Variant = 1 for pre-defined "key encryption key" (KEK). Variant = 2 for password-based encryption. + */ + + + addRecipientByPreDefinedData(preDefinedData, parameters, variant) { + //region Initial variables + const encryptionParameters = parameters || {}; //endregion + //region Check initial parameters + + if (preDefinedData instanceof ArrayBuffer === false) throw new Error("Please pass \"preDefinedData\" in ArrayBuffer type"); + if (preDefinedData.byteLength === 0) throw new Error("Pre-defined data could have zero length"); //endregion + //region Initialize encryption parameters + + if ("keyIdentifier" in encryptionParameters === false) { + const keyIdentifierBuffer = new ArrayBuffer(16); + const keyIdentifierView = new Uint8Array(keyIdentifierBuffer); + (0, _common.getRandomValues)(keyIdentifierView); + encryptionParameters.keyIdentifier = keyIdentifierBuffer; + } + + if ("hmacHashAlgorithm" in encryptionParameters === false) encryptionParameters.hmacHashAlgorithm = "SHA-512"; + if ("iterationCount" in encryptionParameters === false) encryptionParameters.iterationCount = 2048; + + if ("keyEncryptionAlgorithm" in encryptionParameters === false) { + encryptionParameters.keyEncryptionAlgorithm = { + name: "AES-KW", + length: 256 + }; + } + + if ("keyEncryptionAlgorithmParams" in encryptionParameters === false) encryptionParameters.keyEncryptionAlgorithmParams = new asn1js.Null(); //endregion + //region Add new recipient based on passed variant + + switch (variant) { + case 1: + // KEKRecipientInfo + { + //region keyEncryptionAlgorithm + const kekOID = (0, _common.getOIDByAlgorithm)(encryptionParameters.keyEncryptionAlgorithm); + if (kekOID === "") throw new Error("Incorrect value for \"keyEncryptionAlgorithm\""); //endregion + //region KEKRecipientInfo + + const keyInfo = new _KEKRecipientInfo.default({ + version: 4, + kekid: new _KEKIdentifier.default({ + keyIdentifier: new asn1js.OctetString({ + valueHex: encryptionParameters.keyIdentifier + }) + }), + keyEncryptionAlgorithm: new _AlgorithmIdentifier.default({ + algorithmId: kekOID, + + /* + For AES-KW params are NULL, but for other algorithm could another situation. + */ + algorithmParams: encryptionParameters.keyEncryptionAlgorithmParams + }), + preDefinedKEK: preDefinedData // "encryptedKey" would be set in "ecrypt" function + + }); //endregion + //region Final values for "CMS_ENVELOPED_DATA" + + this.recipientInfos.push(new _RecipientInfo.default({ + variant: 3, + value: keyInfo + })); //endregion + } + break; + + case 2: + // PasswordRecipientinfo + { + //region keyDerivationAlgorithm + const pbkdf2OID = (0, _common.getOIDByAlgorithm)({ + name: "PBKDF2" + }); + if (pbkdf2OID === "") throw new Error("Can not find OID for PBKDF2"); //endregion + //region Salt + + const saltBuffer = new ArrayBuffer(64); + const saltView = new Uint8Array(saltBuffer); + (0, _common.getRandomValues)(saltView); //endregion + //region HMAC-based algorithm + + const hmacOID = (0, _common.getOIDByAlgorithm)({ + name: "HMAC", + hash: { + name: encryptionParameters.hmacHashAlgorithm + } + }); + if (hmacOID === "") throw new Error(`Incorrect value for "hmacHashAlgorithm": ${encryptionParameters.hmacHashAlgorithm}`); //endregion + //region PBKDF2-params + + const pbkdf2Params = new _PBKDF2Params.default({ + salt: new asn1js.OctetString({ + valueHex: saltBuffer + }), + iterationCount: encryptionParameters.iterationCount, + prf: new _AlgorithmIdentifier.default({ + algorithmId: hmacOID, + algorithmParams: new asn1js.Null() + }) + }); //endregion + //region keyEncryptionAlgorithm + + const kekOID = (0, _common.getOIDByAlgorithm)(encryptionParameters.keyEncryptionAlgorithm); + if (kekOID === "") throw new Error("Incorrect value for \"keyEncryptionAlgorithm\""); //endregion + //region PasswordRecipientinfo + + const keyInfo = new _PasswordRecipientinfo.default({ + version: 0, + keyDerivationAlgorithm: new _AlgorithmIdentifier.default({ + algorithmId: pbkdf2OID, + algorithmParams: pbkdf2Params.toSchema() + }), + keyEncryptionAlgorithm: new _AlgorithmIdentifier.default({ + algorithmId: kekOID, + + /* + For AES-KW params are NULL, but for other algorithm could be another situation. + */ + algorithmParams: encryptionParameters.keyEncryptionAlgorithmParams + }), + password: preDefinedData // "encryptedKey" would be set in "ecrypt" function + + }); //endregion + //region Final values for "CMS_ENVELOPED_DATA" + + this.recipientInfos.push(new _RecipientInfo.default({ + variant: 4, + value: keyInfo + })); //endregion + } + break; + + default: + throw new Error(`Unknown value for "variant": ${variant}`); + } //endregion + + } //********************************************************************************** + + /** + * Create a new CMS Enveloped Data content with encrypted data + * @param {Object} contentEncryptionAlgorithm WebCrypto algorithm. For the moment here could be only "AES-CBC" or "AES-GCM" algorithms. + * @param {ArrayBuffer} contentToEncrypt Content to encrypt + * @returns {Promise} + */ + + + encrypt(contentEncryptionAlgorithm, contentToEncrypt) { + //region Initial variables + let sequence = Promise.resolve(); + const ivBuffer = new ArrayBuffer(16); // For AES we need IV 16 bytes long + + const ivView = new Uint8Array(ivBuffer); + (0, _common.getRandomValues)(ivView); + const contentView = new Uint8Array(contentToEncrypt); + let sessionKey; + let encryptedContent; + let exportedSessionKey; + const recipientsPromises = []; + + const _this = this; //endregion + //region Check for input parameters + + + const contentEncryptionOID = (0, _common.getOIDByAlgorithm)(contentEncryptionAlgorithm); + if (contentEncryptionOID === "") return Promise.reject("Wrong \"contentEncryptionAlgorithm\" value"); //endregion + //region Get a "crypto" extension + + const crypto = (0, _common.getCrypto)(); + if (typeof crypto === "undefined") return Promise.reject("Unable to create WebCrypto object"); //endregion + //region Generate new content encryption key + + sequence = sequence.then(() => crypto.generateKey(contentEncryptionAlgorithm, true, ["encrypt"])); //endregion + //region Encrypt content + + sequence = sequence.then(result => { + sessionKey = result; + return crypto.encrypt({ + name: contentEncryptionAlgorithm.name, + iv: ivView + }, sessionKey, contentView); + }, error => Promise.reject(error)); //endregion + //region Export raw content of content encryption key + + sequence = sequence.then(result => { + //region Create output OCTETSTRING with encrypted content + encryptedContent = result; //endregion + + return crypto.exportKey("raw", sessionKey); + }, error => Promise.reject(error)).then(result => { + exportedSessionKey = result; + return true; + }, error => Promise.reject(error)); //endregion + //region Append common information to CMS_ENVELOPED_DATA + + sequence = sequence.then(() => { + this.version = 2; + this.encryptedContentInfo = new _EncryptedContentInfo.default({ + contentType: "1.2.840.113549.1.7.1", + // "data" + contentEncryptionAlgorithm: new _AlgorithmIdentifier.default({ + algorithmId: contentEncryptionOID, + algorithmParams: new asn1js.OctetString({ + valueHex: ivBuffer + }) + }), + encryptedContent: new asn1js.OctetString({ + valueHex: encryptedContent + }) + }); + }, error => Promise.reject(error)); //endregion + //region Special sub-functions to work with each recipient's type + + function SubKeyAgreeRecipientInfo(index) { + //region Initial variables + let currentSequence = Promise.resolve(); + let ecdhPublicKey; + let ecdhPrivateKey; + let recipientCurve; + let recipientCurveLength; + let exportedECDHPublicKey; //endregion + //region Get "namedCurve" parameter from recipient's certificate + + currentSequence = currentSequence.then(() => { + const curveObject = _this.recipientInfos[index].value.recipientCertificate.subjectPublicKeyInfo.algorithm.algorithmParams; + if (curveObject instanceof asn1js.ObjectIdentifier === false) return Promise.reject(`Incorrect "recipientCertificate" for index ${index}`); + const curveOID = curveObject.valueBlock.toString(); + + switch (curveOID) { + case "1.2.840.10045.3.1.7": + recipientCurve = "P-256"; + recipientCurveLength = 256; + break; + + case "1.3.132.0.34": + recipientCurve = "P-384"; + recipientCurveLength = 384; + break; + + case "1.3.132.0.35": + recipientCurve = "P-521"; + recipientCurveLength = 528; + break; + + default: + return Promise.reject(`Incorrect curve OID for index ${index}`); + } + + return recipientCurve; + }, error => Promise.reject(error)); //endregion + //region Generate ephemeral ECDH key + + currentSequence = currentSequence.then(result => crypto.generateKey({ + name: "ECDH", + namedCurve: result + }, true, ["deriveBits"]), error => Promise.reject(error)); //endregion + //region Export public key of ephemeral ECDH key pair + + currentSequence = currentSequence.then(result => { + ecdhPublicKey = result.publicKey; + ecdhPrivateKey = result.privateKey; + return crypto.exportKey("spki", ecdhPublicKey); + }, error => Promise.reject(error)); //endregion + //region Import recipient's public key + + currentSequence = currentSequence.then(result => { + exportedECDHPublicKey = result; + return _this.recipientInfos[index].value.recipientCertificate.getPublicKey({ + algorithm: { + algorithm: { + name: "ECDH", + namedCurve: recipientCurve + }, + usages: [] + } + }); + }, error => Promise.reject(error)); //endregion + //region Create shared secret + + currentSequence = currentSequence.then(result => crypto.deriveBits({ + name: "ECDH", + public: result + }, ecdhPrivateKey, recipientCurveLength), error => Promise.reject(error)); //endregion + //region Apply KDF function to shared secret + + currentSequence = currentSequence.then( + /** + * @param {ArrayBuffer} result + */ + result => { + //region Get length of used AES-KW algorithm + const aesKWAlgorithm = new _AlgorithmIdentifier.default({ + schema: _this.recipientInfos[index].value.keyEncryptionAlgorithm.algorithmParams + }); + const KWalgorithm = (0, _common.getAlgorithmByOID)(aesKWAlgorithm.algorithmId); + if ("name" in KWalgorithm === false) return Promise.reject(`Incorrect OID for key encryption algorithm: ${aesKWAlgorithm.algorithmId}`); //endregion + //region Translate AES-KW length to ArrayBuffer + + let kwLength = KWalgorithm.length; + const kwLengthBuffer = new ArrayBuffer(4); + const kwLengthView = new Uint8Array(kwLengthBuffer); + + for (let j = 3; j >= 0; j--) { + kwLengthView[j] = kwLength; + kwLength >>= 8; + } //endregion + //region Create and encode "ECC-CMS-SharedInfo" structure + + + const eccInfo = new _ECCCMSSharedInfo.default({ + keyInfo: new _AlgorithmIdentifier.default({ + algorithmId: aesKWAlgorithm.algorithmId, + + /* + Initially RFC5753 says that AES algorithms have absent parameters. + But since early implementations all put NULL here. Thus, in order to be + "backward compatible", index also put NULL here. + */ + algorithmParams: new asn1js.Null() + }), + entityUInfo: _this.recipientInfos[index].value.ukm, + suppPubInfo: new asn1js.OctetString({ + valueHex: kwLengthBuffer + }) + }); + const encodedInfo = eccInfo.toSchema().toBER(false); //endregion + //region Get SHA algorithm used together with ECDH + + const ecdhAlgorithm = (0, _common.getAlgorithmByOID)(_this.recipientInfos[index].value.keyEncryptionAlgorithm.algorithmId); + if ("name" in ecdhAlgorithm === false) return Promise.reject(`Incorrect OID for key encryption algorithm: ${_this.recipientInfos[index].value.keyEncryptionAlgorithm.algorithmId}`); //endregion + + return (0, _common.kdf)(ecdhAlgorithm.kdf, result, KWalgorithm.length, encodedInfo); + }, error => Promise.reject(error)); //endregion + //region Import AES-KW key from result of KDF function + + currentSequence = currentSequence.then(result => crypto.importKey("raw", result, { + name: "AES-KW" + }, true, ["wrapKey"]), error => Promise.reject(error)); //endregion + //region Finally wrap session key by using AES-KW algorithm + + currentSequence = currentSequence.then(result => crypto.wrapKey("raw", sessionKey, result, { + name: "AES-KW" + }), error => Promise.reject(error)); //endregion + //region Append all neccessary data to current CMS_RECIPIENT_INFO object + + currentSequence = currentSequence.then(result => { + //region OriginatorIdentifierOrKey + const asn1 = asn1js.fromBER(exportedECDHPublicKey); + const originator = new _OriginatorIdentifierOrKey.default(); + originator.variant = 3; + originator.value = new _OriginatorPublicKey.default({ + schema: asn1.result + }); // There is option when we can stay with ECParameters, but here index prefer to avoid the params + + if ("algorithmParams" in originator.value.algorithm) delete originator.value.algorithm.algorithmParams; + _this.recipientInfos[index].value.originator = originator; //endregion + //region RecipientEncryptedKey + + /* + We will not support using of same ephemeral key for many recipients + */ + + _this.recipientInfos[index].value.recipientEncryptedKeys.encryptedKeys[0].encryptedKey = new asn1js.OctetString({ + valueHex: result + }); //endregion + }, error => Promise.reject(error)); //endregion + + return currentSequence; + } + + function SubKeyTransRecipientInfo(index) { + //region Initial variables + let currentSequence = Promise.resolve(); //endregion + //region Get recipient's public key + + currentSequence = currentSequence.then(() => { + //region Get current used SHA algorithm + const schema = _this.recipientInfos[index].value.keyEncryptionAlgorithm.algorithmParams; + const rsaOAEPParams = new _RSAESOAEPParams.default({ + schema + }); + const hashAlgorithm = (0, _common.getAlgorithmByOID)(rsaOAEPParams.hashAlgorithm.algorithmId); + if ("name" in hashAlgorithm === false) return Promise.reject(`Incorrect OID for hash algorithm: ${rsaOAEPParams.hashAlgorithm.algorithmId}`); //endregion + + return _this.recipientInfos[index].value.recipientCertificate.getPublicKey({ + algorithm: { + algorithm: { + name: "RSA-OAEP", + hash: { + name: hashAlgorithm.name + } + }, + usages: ["encrypt", "wrapKey"] + } + }); + }, error => Promise.reject(error)); //endregion + //region Encrypt early exported session key on recipient's public key + + currentSequence = currentSequence.then(result => crypto.encrypt(result.algorithm, result, exportedSessionKey), error => Promise.reject(error)); //endregion + //region Append all neccessary data to current CMS_RECIPIENT_INFO object + + currentSequence = currentSequence.then(result => { + //region RecipientEncryptedKey + _this.recipientInfos[index].value.encryptedKey = new asn1js.OctetString({ + valueHex: result + }); //endregion + }, error => Promise.reject(error)); //endregion + + return currentSequence; + } + + function SubKEKRecipientInfo(index) { + //region Initial variables + let currentSequence = Promise.resolve(); + let kekAlgorithm; //endregion + //region Import KEK from pre-defined data + + currentSequence = currentSequence.then(() => { + //region Get WebCrypto form of "keyEncryptionAlgorithm" + kekAlgorithm = (0, _common.getAlgorithmByOID)(_this.recipientInfos[index].value.keyEncryptionAlgorithm.algorithmId); + if ("name" in kekAlgorithm === false) return Promise.reject(`Incorrect OID for "keyEncryptionAlgorithm": ${_this.recipientInfos[index].value.keyEncryptionAlgorithm.algorithmId}`); //endregion + + return crypto.importKey("raw", new Uint8Array(_this.recipientInfos[index].value.preDefinedKEK), kekAlgorithm, true, ["wrapKey"]); // Too specific for AES-KW + }, error => Promise.reject(error)); //endregion + //region Wrap previously exported session key + + currentSequence = currentSequence.then(result => crypto.wrapKey("raw", sessionKey, result, kekAlgorithm), error => Promise.reject(error)); //endregion + //region Append all neccessary data to current CMS_RECIPIENT_INFO object + + currentSequence = currentSequence.then(result => { + //region RecipientEncryptedKey + _this.recipientInfos[index].value.encryptedKey = new asn1js.OctetString({ + valueHex: result + }); //endregion + }, error => Promise.reject(error)); //endregion + + return currentSequence; + } + + function SubPasswordRecipientinfo(index) { + //region Initial variables + let currentSequence = Promise.resolve(); + let pbkdf2Params; + let kekAlgorithm; //endregion + //region Check that we have encoded "keyDerivationAlgorithm" plus "PBKDF2_params" in there + + currentSequence = currentSequence.then(() => { + if ("keyDerivationAlgorithm" in _this.recipientInfos[index].value === false) return Promise.reject("Please append encoded \"keyDerivationAlgorithm\""); + if ("algorithmParams" in _this.recipientInfos[index].value.keyDerivationAlgorithm === false) return Promise.reject("Incorrectly encoded \"keyDerivationAlgorithm\""); + + try { + pbkdf2Params = new _PBKDF2Params.default({ + schema: _this.recipientInfos[index].value.keyDerivationAlgorithm.algorithmParams + }); + } catch (ex) { + return Promise.reject("Incorrectly encoded \"keyDerivationAlgorithm\""); + } + + return Promise.resolve(); + }, error => Promise.reject(error)); //endregion + //region Derive PBKDF2 key from "password" buffer + + currentSequence = currentSequence.then(() => { + const passwordView = new Uint8Array(_this.recipientInfos[index].value.password); + return crypto.importKey("raw", passwordView, "PBKDF2", false, ["deriveKey"]); + }, error => Promise.reject(error)); //endregion + //region Derive key for "keyEncryptionAlgorithm" + + currentSequence = currentSequence.then(result => { + //region Get WebCrypto form of "keyEncryptionAlgorithm" + kekAlgorithm = (0, _common.getAlgorithmByOID)(_this.recipientInfos[index].value.keyEncryptionAlgorithm.algorithmId); + if ("name" in kekAlgorithm === false) return Promise.reject(`Incorrect OID for "keyEncryptionAlgorithm": ${_this.recipientInfos[index].value.keyEncryptionAlgorithm.algorithmId}`); //endregion + //region Get HMAC hash algorithm + + let hmacHashAlgorithm = "SHA-1"; + + if ("prf" in pbkdf2Params) { + const algorithm = (0, _common.getAlgorithmByOID)(pbkdf2Params.prf.algorithmId); + if ("name" in algorithm === false) return Promise.reject("Incorrect OID for HMAC hash algorithm"); + hmacHashAlgorithm = algorithm.hash.name; + } //endregion + //region Get PBKDF2 "salt" value + + + const saltView = new Uint8Array(pbkdf2Params.salt.valueBlock.valueHex); //endregion + //region Get PBKDF2 iterations count + + const iterations = pbkdf2Params.iterationCount; //endregion + + return crypto.deriveKey({ + name: "PBKDF2", + hash: { + name: hmacHashAlgorithm + }, + salt: saltView, + iterations + }, result, kekAlgorithm, true, ["wrapKey"]); // Usages are too specific for KEK algorithm + }, error => Promise.reject(error)); //endregion + //region Wrap previously exported session key (Also too specific for KEK algorithm) + + currentSequence = currentSequence.then(result => crypto.wrapKey("raw", sessionKey, result, kekAlgorithm), error => Promise.reject(error)); //endregion + //region Append all neccessary data to current CMS_RECIPIENT_INFO object + + currentSequence = currentSequence.then(result => { + //region RecipientEncryptedKey + _this.recipientInfos[index].value.encryptedKey = new asn1js.OctetString({ + valueHex: result + }); //endregion + }, error => Promise.reject(error)); //endregion + + return currentSequence; + } //endregion + //region Create special routines for each "recipient" + + + sequence = sequence.then(() => { + for (let i = 0; i < this.recipientInfos.length; i++) { + //region Initial variables + let currentSequence = Promise.resolve(); //endregion + + switch (this.recipientInfos[i].variant) { + case 1: + // KeyTransRecipientInfo + currentSequence = SubKeyTransRecipientInfo(i); + break; + + case 2: + // KeyAgreeRecipientInfo + currentSequence = SubKeyAgreeRecipientInfo(i); + break; + + case 3: + // KEKRecipientInfo + currentSequence = SubKEKRecipientInfo(i); + break; + + case 4: + // PasswordRecipientinfo + currentSequence = SubPasswordRecipientinfo(i); + break; + + default: + return Promise.reject(`Uknown recipient type in array with index ${i}`); + } + + recipientsPromises.push(currentSequence); + } + + return Promise.all(recipientsPromises); + }, error => Promise.reject(error)); //endregion + + return sequence; + } //********************************************************************************** + + /** + * Decrypt existing CMS Enveloped Data content + * @param {number} recipientIndex Index of recipient + * @param {Object} parameters Additional parameters + * @returns {Promise} + */ + + + decrypt(recipientIndex, parameters) { + //region Initial variables + let sequence = Promise.resolve(); + const decryptionParameters = parameters || {}; + + const _this = this; //endregion + //region Check for input parameters + + + if (recipientIndex + 1 > this.recipientInfos.length) return Promise.reject(`Maximum value for "index" is: ${this.recipientInfos.length - 1}`); //endregion + //region Get a "crypto" extension + + const crypto = (0, _common.getCrypto)(); + if (typeof crypto === "undefined") return Promise.reject("Unable to create WebCrypto object"); //endregion + //region Special sub-functions to work with each recipient's type + + function SubKeyAgreeRecipientInfo(index) { + //region Initial variables + let currentSequence = Promise.resolve(); + let recipientCurve; + let recipientCurveLength; + let curveOID; + let ecdhPrivateKey; //endregion + //region Get "namedCurve" parameter from recipient's certificate + + currentSequence = currentSequence.then(() => { + if ("recipientCertificate" in decryptionParameters === false) return Promise.reject("Parameter \"recipientCertificate\" is mandatory for \"KeyAgreeRecipientInfo\""); + if ("recipientPrivateKey" in decryptionParameters === false) return Promise.reject("Parameter \"recipientPrivateKey\" is mandatory for \"KeyAgreeRecipientInfo\""); + const curveObject = decryptionParameters.recipientCertificate.subjectPublicKeyInfo.algorithm.algorithmParams; + if (curveObject instanceof asn1js.ObjectIdentifier === false) return Promise.reject(`Incorrect "recipientCertificate" for index ${index}`); + curveOID = curveObject.valueBlock.toString(); + + switch (curveOID) { + case "1.2.840.10045.3.1.7": + recipientCurve = "P-256"; + recipientCurveLength = 256; + break; + + case "1.3.132.0.34": + recipientCurve = "P-384"; + recipientCurveLength = 384; + break; + + case "1.3.132.0.35": + recipientCurve = "P-521"; + recipientCurveLength = 528; + break; + + default: + return Promise.reject(`Incorrect curve OID for index ${index}`); + } + + return crypto.importKey("pkcs8", decryptionParameters.recipientPrivateKey, { + name: "ECDH", + namedCurve: recipientCurve + }, true, ["deriveBits"]); + }, error => Promise.reject(error)); //endregion + //region Import sender's ephemeral public key + + currentSequence = currentSequence.then(result => { + ecdhPrivateKey = result; //region Change "OriginatorPublicKey" if "curve" parameter absent + + if ("algorithmParams" in _this.recipientInfos[index].value.originator.value.algorithm === false) _this.recipientInfos[index].value.originator.value.algorithm.algorithmParams = new asn1js.ObjectIdentifier({ + value: curveOID + }); //endregion + //region Create ArrayBuffer with sender's public key + + const buffer = _this.recipientInfos[index].value.originator.value.toSchema().toBER(false); //endregion + + + return crypto.importKey("spki", buffer, { + name: "ECDH", + namedCurve: recipientCurve + }, true, []); + }, error => Promise.reject(error)); //endregion + //region Create shared secret + + currentSequence = currentSequence.then(result => crypto.deriveBits({ + name: "ECDH", + public: result + }, ecdhPrivateKey, recipientCurveLength), error => Promise.reject(error)); //endregion + //region Apply KDF function to shared secret + + currentSequence = currentSequence.then( + /** + * @param {ArrayBuffer} result + */ + result => { + //region Get length of used AES-KW algorithm + const aesKWAlgorithm = new _AlgorithmIdentifier.default({ + schema: _this.recipientInfos[index].value.keyEncryptionAlgorithm.algorithmParams + }); + const KWalgorithm = (0, _common.getAlgorithmByOID)(aesKWAlgorithm.algorithmId); + if ("name" in KWalgorithm === false) return Promise.reject(`Incorrect OID for key encryption algorithm: ${aesKWAlgorithm.algorithmId}`); //endregion + //region Translate AES-KW length to ArrayBuffer + + let kwLength = KWalgorithm.length; + const kwLengthBuffer = new ArrayBuffer(4); + const kwLengthView = new Uint8Array(kwLengthBuffer); + + for (let j = 3; j >= 0; j--) { + kwLengthView[j] = kwLength; + kwLength >>= 8; + } //endregion + //region Create and encode "ECC-CMS-SharedInfo" structure + + + const eccInfo = new _ECCCMSSharedInfo.default({ + keyInfo: new _AlgorithmIdentifier.default({ + algorithmId: aesKWAlgorithm.algorithmId, + + /* + Initially RFC5753 says that AES algorithms have absent parameters. + But since early implementations all put NULL here. Thus, in order to be + "backward compatible", index also put NULL here. + */ + algorithmParams: new asn1js.Null() + }), + entityUInfo: _this.recipientInfos[index].value.ukm, + suppPubInfo: new asn1js.OctetString({ + valueHex: kwLengthBuffer + }) + }); + const encodedInfo = eccInfo.toSchema().toBER(false); //endregion + //region Get SHA algorithm used together with ECDH + + const ecdhAlgorithm = (0, _common.getAlgorithmByOID)(_this.recipientInfos[index].value.keyEncryptionAlgorithm.algorithmId); + if ("name" in ecdhAlgorithm === false) return Promise.reject(`Incorrect OID for key encryption algorithm: ${_this.recipientInfos[index].value.keyEncryptionAlgorithm.algorithmId}`); //endregion + + return (0, _common.kdf)(ecdhAlgorithm.kdf, result, KWalgorithm.length, encodedInfo); + }, error => Promise.reject(error)); //endregion + //region Import AES-KW key from result of KDF function + + currentSequence = currentSequence.then(result => crypto.importKey("raw", result, { + name: "AES-KW" + }, true, ["unwrapKey"]), error => Promise.reject(error)); //endregion + //region Finally unwrap session key + + currentSequence = currentSequence.then(result => { + //region Get WebCrypto form of content encryption algorithm + const contentEncryptionAlgorithm = (0, _common.getAlgorithmByOID)(_this.encryptedContentInfo.contentEncryptionAlgorithm.algorithmId); + if ("name" in contentEncryptionAlgorithm === false) return Promise.reject(`Incorrect "contentEncryptionAlgorithm": ${_this.encryptedContentInfo.contentEncryptionAlgorithm.algorithmId}`); //endregion + + return crypto.unwrapKey("raw", _this.recipientInfos[index].value.recipientEncryptedKeys.encryptedKeys[0].encryptedKey.valueBlock.valueHex, result, { + name: "AES-KW" + }, contentEncryptionAlgorithm, true, ["decrypt"]); + }, error => Promise.reject(error)); //endregion + + return currentSequence; + } + + function SubKeyTransRecipientInfo(index) { + //region Initial variables + let currentSequence = Promise.resolve(); //endregion + //region Import recipient's private key + + currentSequence = currentSequence.then(() => { + if ("recipientPrivateKey" in decryptionParameters === false) return Promise.reject("Parameter \"recipientPrivateKey\" is mandatory for \"KeyTransRecipientInfo\""); //region Get current used SHA algorithm + + const schema = _this.recipientInfos[index].value.keyEncryptionAlgorithm.algorithmParams; + const rsaOAEPParams = new _RSAESOAEPParams.default({ + schema + }); + const hashAlgorithm = (0, _common.getAlgorithmByOID)(rsaOAEPParams.hashAlgorithm.algorithmId); + if ("name" in hashAlgorithm === false) return Promise.reject(`Incorrect OID for hash algorithm: ${rsaOAEPParams.hashAlgorithm.algorithmId}`); //endregion + + return crypto.importKey("pkcs8", decryptionParameters.recipientPrivateKey, { + name: "RSA-OAEP", + hash: { + name: hashAlgorithm.name + } + }, true, ["decrypt"]); + }, error => Promise.reject(error)); //endregion + //region Decrypt encrypted session key + + currentSequence = currentSequence.then(result => crypto.decrypt(result.algorithm, result, _this.recipientInfos[index].value.encryptedKey.valueBlock.valueHex), error => Promise.reject(error)); //endregion + //region Import decrypted session key + + currentSequence = currentSequence.then(result => { + //region Get WebCrypto form of content encryption algorithm + const contentEncryptionAlgorithm = (0, _common.getAlgorithmByOID)(_this.encryptedContentInfo.contentEncryptionAlgorithm.algorithmId); + if ("name" in contentEncryptionAlgorithm === false) return Promise.reject(`Incorrect "contentEncryptionAlgorithm": ${_this.encryptedContentInfo.contentEncryptionAlgorithm.algorithmId}`); //endregion + + return crypto.importKey("raw", result, contentEncryptionAlgorithm, true, ["decrypt"]); + }, error => Promise.reject(error)); //endregion + + return currentSequence; + } + + function SubKEKRecipientInfo(index) { + //region Initial variables + let currentSequence = Promise.resolve(); + let kekAlgorithm; //endregion + //region Import KEK from pre-defined data + + currentSequence = currentSequence.then(() => { + if ("preDefinedData" in decryptionParameters === false) return Promise.reject("Parameter \"preDefinedData\" is mandatory for \"KEKRecipientInfo\""); //region Get WebCrypto form of "keyEncryptionAlgorithm" + + kekAlgorithm = (0, _common.getAlgorithmByOID)(_this.recipientInfos[index].value.keyEncryptionAlgorithm.algorithmId); + if ("name" in kekAlgorithm === false) return Promise.reject(`Incorrect OID for "keyEncryptionAlgorithm": ${_this.recipientInfos[index].value.keyEncryptionAlgorithm.algorithmId}`); //endregion + + return crypto.importKey("raw", decryptionParameters.preDefinedData, kekAlgorithm, true, ["unwrapKey"]); // Too specific for AES-KW + }, error => Promise.reject(error)); //endregion + //region Unwrap previously exported session key + + currentSequence = currentSequence.then(result => { + //region Get WebCrypto form of content encryption algorithm + const contentEncryptionAlgorithm = (0, _common.getAlgorithmByOID)(_this.encryptedContentInfo.contentEncryptionAlgorithm.algorithmId); + if ("name" in contentEncryptionAlgorithm === false) return Promise.reject(`Incorrect "contentEncryptionAlgorithm": ${_this.encryptedContentInfo.contentEncryptionAlgorithm.algorithmId}`); //endregion + + return crypto.unwrapKey("raw", _this.recipientInfos[index].value.encryptedKey.valueBlock.valueHex, result, kekAlgorithm, contentEncryptionAlgorithm, true, ["decrypt"]); + }, error => Promise.reject(error)); //endregion + + return currentSequence; + } + + function SubPasswordRecipientinfo(index) { + //region Initial variables + let currentSequence = Promise.resolve(); + let pbkdf2Params; + let kekAlgorithm; //endregion + //region Derive PBKDF2 key from "password" buffer + + currentSequence = currentSequence.then(() => { + if ("preDefinedData" in decryptionParameters === false) return Promise.reject("Parameter \"preDefinedData\" is mandatory for \"KEKRecipientInfo\""); + if ("keyDerivationAlgorithm" in _this.recipientInfos[index].value === false) return Promise.reject("Please append encoded \"keyDerivationAlgorithm\""); + if ("algorithmParams" in _this.recipientInfos[index].value.keyDerivationAlgorithm === false) return Promise.reject("Incorrectly encoded \"keyDerivationAlgorithm\""); + + try { + pbkdf2Params = new _PBKDF2Params.default({ + schema: _this.recipientInfos[index].value.keyDerivationAlgorithm.algorithmParams + }); + } catch (ex) { + return Promise.reject("Incorrectly encoded \"keyDerivationAlgorithm\""); + } + + return crypto.importKey("raw", decryptionParameters.preDefinedData, "PBKDF2", false, ["deriveKey"]); + }, error => Promise.reject(error)); //endregion + //region Derive key for "keyEncryptionAlgorithm" + + currentSequence = currentSequence.then(result => { + //region Get WebCrypto form of "keyEncryptionAlgorithm" + kekAlgorithm = (0, _common.getAlgorithmByOID)(_this.recipientInfos[index].value.keyEncryptionAlgorithm.algorithmId); + if ("name" in kekAlgorithm === false) return Promise.reject(`Incorrect OID for "keyEncryptionAlgorithm": ${_this.recipientInfos[index].value.keyEncryptionAlgorithm.algorithmId}`); //endregion + //region Get HMAC hash algorithm + + let hmacHashAlgorithm = "SHA-1"; + + if ("prf" in pbkdf2Params) { + const algorithm = (0, _common.getAlgorithmByOID)(pbkdf2Params.prf.algorithmId); + if ("name" in algorithm === false) return Promise.reject("Incorrect OID for HMAC hash algorithm"); + hmacHashAlgorithm = algorithm.hash.name; + } //endregion + //region Get PBKDF2 "salt" value + + + const saltView = new Uint8Array(pbkdf2Params.salt.valueBlock.valueHex); //endregion + //region Get PBKDF2 iterations count + + const iterations = pbkdf2Params.iterationCount; //endregion + + return crypto.deriveKey({ + name: "PBKDF2", + hash: { + name: hmacHashAlgorithm + }, + salt: saltView, + iterations + }, result, kekAlgorithm, true, ["unwrapKey"]); // Usages are too specific for KEK algorithm + }, error => Promise.reject(error)); //endregion + //region Unwrap previously exported session key + + currentSequence = currentSequence.then(result => { + //region Get WebCrypto form of content encryption algorithm + const contentEncryptionAlgorithm = (0, _common.getAlgorithmByOID)(_this.encryptedContentInfo.contentEncryptionAlgorithm.algorithmId); + if ("name" in contentEncryptionAlgorithm === false) return Promise.reject(`Incorrect "contentEncryptionAlgorithm": ${_this.encryptedContentInfo.contentEncryptionAlgorithm.algorithmId}`); //endregion + + return crypto.unwrapKey("raw", _this.recipientInfos[index].value.encryptedKey.valueBlock.valueHex, result, kekAlgorithm, contentEncryptionAlgorithm, true, ["decrypt"]); + }, error => Promise.reject(error)); //endregion + + return currentSequence; + } //endregion + //region Perform steps, specific to each type of session key encryption + + + sequence = sequence.then(() => { + //region Initial variables + let currentSequence = Promise.resolve(); //endregion + + switch (this.recipientInfos[recipientIndex].variant) { + case 1: + // KeyTransRecipientInfo + currentSequence = SubKeyTransRecipientInfo(recipientIndex); + break; + + case 2: + // KeyAgreeRecipientInfo + currentSequence = SubKeyAgreeRecipientInfo(recipientIndex); + break; + + case 3: + // KEKRecipientInfo + currentSequence = SubKEKRecipientInfo(recipientIndex); + break; + + case 4: + // PasswordRecipientinfo + currentSequence = SubPasswordRecipientinfo(recipientIndex); + break; + + default: + return Promise.reject(`Uknown recipient type in array with index ${recipientIndex}`); + } + + return currentSequence; + }, error => Promise.reject(error)); //endregion + //region Finally decrypt data by session key + + sequence = sequence.then(result => { + //region Get WebCrypto form of content encryption algorithm + const contentEncryptionAlgorithm = (0, _common.getAlgorithmByOID)(this.encryptedContentInfo.contentEncryptionAlgorithm.algorithmId); + if ("name" in contentEncryptionAlgorithm === false) return Promise.reject(`Incorrect "contentEncryptionAlgorithm": ${this.encryptedContentInfo.contentEncryptionAlgorithm.algorithmId}`); //endregion + //region Get "intialization vector" for content encryption algorithm + + const ivBuffer = this.encryptedContentInfo.contentEncryptionAlgorithm.algorithmParams.valueBlock.valueHex; + const ivView = new Uint8Array(ivBuffer); //endregion + //region Create correct data block for decryption + + let dataBuffer = new ArrayBuffer(0); + if (this.encryptedContentInfo.encryptedContent.idBlock.isConstructed === false) dataBuffer = this.encryptedContentInfo.encryptedContent.valueBlock.valueHex;else { + var _iteratorNormalCompletion = true; + var _didIteratorError = false; + var _iteratorError = undefined; + + try { + for (var _iterator = this.encryptedContentInfo.encryptedContent.valueBlock.value[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { + const content = _step.value; + dataBuffer = (0, _pvutils.utilConcatBuf)(dataBuffer, content.valueBlock.valueHex); + } + } catch (err) { + _didIteratorError = true; + _iteratorError = err; + } finally { + try { + if (!_iteratorNormalCompletion && _iterator.return != null) { + _iterator.return(); + } + } finally { + if (_didIteratorError) { + throw _iteratorError; + } + } + } + } //endregion + + return crypto.decrypt({ + name: contentEncryptionAlgorithm.name, + iv: ivView + }, result, dataBuffer); + }, error => Promise.reject(error)); //endregion + + return sequence; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = EnvelopedData; + +},{"./AlgorithmIdentifier.js":4,"./Attribute.js":6,"./ECCCMSSharedInfo.js":30,"./EncryptedContentInfo.js":34,"./IssuerAndSerialNumber.js":44,"./KEKIdentifier.js":46,"./KEKRecipientInfo.js":47,"./KeyAgreeRecipientIdentifier.js":48,"./KeyAgreeRecipientInfo.js":49,"./KeyTransRecipientInfo.js":51,"./OriginatorIdentifierOrKey.js":57,"./OriginatorInfo.js":58,"./OriginatorPublicKey.js":59,"./PBKDF2Params.js":66,"./PasswordRecipientinfo.js":70,"./RSAESOAEPParams.js":80,"./RecipientEncryptedKey.js":84,"./RecipientEncryptedKeys.js":85,"./RecipientInfo.js":87,"./common.js":110,"asn1js":112,"pvutils":113}],37:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC5280 + */ +class ExtKeyUsage { + //********************************************************************************** + + /** + * Constructor for ExtKeyUsage class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {Array.} + * @desc keyPurposes + */ + this.keyPurposes = (0, _pvutils.getParametersValue)(parameters, "keyPurposes", ExtKeyUsage.defaultValues("keyPurposes")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "keyPurposes": + return []; + + default: + throw new Error(`Invalid member name for ExtKeyUsage class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * ExtKeyUsage ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId + * + * KeyPurposeId ::= OBJECT IDENTIFIER + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [keyPurposes] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [new asn1js.Repeated({ + name: names.keyPurposes || "", + value: new asn1js.ObjectIdentifier() + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["keyPurposes"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, ExtKeyUsage.schema({ + names: { + keyPurposes: "keyPurposes" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for ExtKeyUsage"); //endregion + //region Get internal properties from parsed schema + + this.keyPurposes = Array.from(asn1.result.keyPurposes, element => element.valueBlock.toString()); //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Construct and return new ASN.1 schema for this object + return new asn1js.Sequence({ + value: Array.from(this.keyPurposes, element => new asn1js.ObjectIdentifier({ + value: element + })) + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + return { + keyPurposes: Array.from(this.keyPurposes) + }; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = ExtKeyUsage; + +},{"asn1js":112,"pvutils":113}],38:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _SubjectDirectoryAttributes = _interopRequireDefault(require("./SubjectDirectoryAttributes.js")); + +var _PrivateKeyUsagePeriod = _interopRequireDefault(require("./PrivateKeyUsagePeriod.js")); + +var _AltName = _interopRequireDefault(require("./AltName.js")); + +var _BasicConstraints = _interopRequireDefault(require("./BasicConstraints.js")); + +var _IssuingDistributionPoint = _interopRequireDefault(require("./IssuingDistributionPoint.js")); + +var _GeneralNames = _interopRequireDefault(require("./GeneralNames.js")); + +var _NameConstraints = _interopRequireDefault(require("./NameConstraints.js")); + +var _CRLDistributionPoints = _interopRequireDefault(require("./CRLDistributionPoints.js")); + +var _CertificatePolicies = _interopRequireDefault(require("./CertificatePolicies.js")); + +var _PolicyMappings = _interopRequireDefault(require("./PolicyMappings.js")); + +var _AuthorityKeyIdentifier = _interopRequireDefault(require("./AuthorityKeyIdentifier.js")); + +var _PolicyConstraints = _interopRequireDefault(require("./PolicyConstraints.js")); + +var _ExtKeyUsage = _interopRequireDefault(require("./ExtKeyUsage.js")); + +var _InfoAccess = _interopRequireDefault(require("./InfoAccess.js")); + +var _SignedCertificateTimestampList = _interopRequireDefault(require("./SignedCertificateTimestampList.js")); + +var _CertificateTemplate = _interopRequireDefault(require("./CertificateTemplate.js")); + +var _CAVersion = _interopRequireDefault(require("./CAVersion.js")); + +var _QCStatements = _interopRequireDefault(require("./QCStatements.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC5280 + */ +class Extension { + //********************************************************************************** + + /** + * Constructor for Extension class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {string} + * @desc extnID + */ + this.extnID = (0, _pvutils.getParametersValue)(parameters, "extnID", Extension.defaultValues("extnID")); + /** + * @type {boolean} + * @desc critical + */ + + this.critical = (0, _pvutils.getParametersValue)(parameters, "critical", Extension.defaultValues("critical")); + /** + * @type {OctetString} + * @desc extnValue + */ + + if ("extnValue" in parameters) this.extnValue = new asn1js.OctetString({ + valueHex: parameters.extnValue + });else this.extnValue = Extension.defaultValues("extnValue"); + if ("parsedValue" in parameters) + /** + * @type {Object} + * @desc parsedValue + */ + this.parsedValue = (0, _pvutils.getParametersValue)(parameters, "parsedValue", Extension.defaultValues("parsedValue")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "extnID": + return ""; + + case "critical": + return false; + + case "extnValue": + return new asn1js.OctetString(); + + case "parsedValue": + return {}; + + default: + throw new Error(`Invalid member name for Extension class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * Extension ::= SEQUENCE { + * extnID OBJECT IDENTIFIER, + * critical BOOLEAN DEFAULT FALSE, + * extnValue OCTET STRING + * } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [extnID] + * @property {string} [critical] + * @property {string} [extnValue] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [new asn1js.ObjectIdentifier({ + name: names.extnID || "" + }), new asn1js.Boolean({ + name: names.critical || "", + optional: true + }), new asn1js.OctetString({ + name: names.extnValue || "" + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["extnID", "critical", "extnValue"]); //endregion + //region Check the schema is valid + + let asn1 = asn1js.compareSchema(schema, schema, Extension.schema({ + names: { + extnID: "extnID", + critical: "critical", + extnValue: "extnValue" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for Extension"); //endregion + //region Get internal properties from parsed schema + + this.extnID = asn1.result.extnID.valueBlock.toString(); + if ("critical" in asn1.result) this.critical = asn1.result.critical.valueBlock.value; + this.extnValue = asn1.result.extnValue; //region Get "parsedValue" for well-known extensions + + asn1 = asn1js.fromBER(this.extnValue.valueBlock.valueHex); + if (asn1.offset === -1) return; + + switch (this.extnID) { + case "2.5.29.9": + // SubjectDirectoryAttributes + try { + this.parsedValue = new _SubjectDirectoryAttributes.default({ + schema: asn1.result + }); + } catch (ex) { + this.parsedValue = new _SubjectDirectoryAttributes.default(); + this.parsedValue.parsingError = "Incorrectly formated SubjectDirectoryAttributes"; + } + + break; + + case "2.5.29.14": + // SubjectKeyIdentifier + this.parsedValue = asn1.result; // Should be just a simple OCTETSTRING + + break; + + case "2.5.29.15": + // KeyUsage + this.parsedValue = asn1.result; // Should be just a simple BITSTRING + + break; + + case "2.5.29.16": + // PrivateKeyUsagePeriod + try { + this.parsedValue = new _PrivateKeyUsagePeriod.default({ + schema: asn1.result + }); + } catch (ex) { + this.parsedValue = new _PrivateKeyUsagePeriod.default(); + this.parsedValue.parsingError = "Incorrectly formated PrivateKeyUsagePeriod"; + } + + break; + + case "2.5.29.17": // SubjectAltName + + case "2.5.29.18": + // IssuerAltName + try { + this.parsedValue = new _AltName.default({ + schema: asn1.result + }); + } catch (ex) { + this.parsedValue = new _AltName.default(); + this.parsedValue.parsingError = "Incorrectly formated AltName"; + } + + break; + + case "2.5.29.19": + // BasicConstraints + try { + this.parsedValue = new _BasicConstraints.default({ + schema: asn1.result + }); + } catch (ex) { + this.parsedValue = new _BasicConstraints.default(); + this.parsedValue.parsingError = "Incorrectly formated BasicConstraints"; + } + + break; + + case "2.5.29.20": // CRLNumber + + case "2.5.29.27": + // BaseCRLNumber (delta CRL indicator) + this.parsedValue = asn1.result; // Should be just a simple INTEGER + + break; + + case "2.5.29.21": + // CRLReason + this.parsedValue = asn1.result; // Should be just a simple ENUMERATED + + break; + + case "2.5.29.24": + // InvalidityDate + this.parsedValue = asn1.result; // Should be just a simple GeneralizedTime + + break; + + case "2.5.29.28": + // IssuingDistributionPoint + try { + this.parsedValue = new _IssuingDistributionPoint.default({ + schema: asn1.result + }); + } catch (ex) { + this.parsedValue = new _IssuingDistributionPoint.default(); + this.parsedValue.parsingError = "Incorrectly formated IssuingDistributionPoint"; + } + + break; + + case "2.5.29.29": + // CertificateIssuer + try { + this.parsedValue = new _GeneralNames.default({ + schema: asn1.result + }); // Should be just a simple + } catch (ex) { + this.parsedValue = new _GeneralNames.default(); + this.parsedValue.parsingError = "Incorrectly formated GeneralNames"; + } + + break; + + case "2.5.29.30": + // NameConstraints + try { + this.parsedValue = new _NameConstraints.default({ + schema: asn1.result + }); + } catch (ex) { + this.parsedValue = new _NameConstraints.default(); + this.parsedValue.parsingError = "Incorrectly formated NameConstraints"; + } + + break; + + case "2.5.29.31": // CRLDistributionPoints + + case "2.5.29.46": + // FreshestCRL + try { + this.parsedValue = new _CRLDistributionPoints.default({ + schema: asn1.result + }); + } catch (ex) { + this.parsedValue = new _CRLDistributionPoints.default(); + this.parsedValue.parsingError = "Incorrectly formated CRLDistributionPoints"; + } + + break; + + case "2.5.29.32": // CertificatePolicies + + case "1.3.6.1.4.1.311.21.10": + // szOID_APPLICATION_CERT_POLICIES - Microsoft-specific OID + try { + this.parsedValue = new _CertificatePolicies.default({ + schema: asn1.result + }); + } catch (ex) { + this.parsedValue = new _CertificatePolicies.default(); + this.parsedValue.parsingError = "Incorrectly formated CertificatePolicies"; + } + + break; + + case "2.5.29.33": + // PolicyMappings + try { + this.parsedValue = new _PolicyMappings.default({ + schema: asn1.result + }); + } catch (ex) { + this.parsedValue = new _PolicyMappings.default(); + this.parsedValue.parsingError = "Incorrectly formated CertificatePolicies"; + } + + break; + + case "2.5.29.35": + // AuthorityKeyIdentifier + try { + this.parsedValue = new _AuthorityKeyIdentifier.default({ + schema: asn1.result + }); + } catch (ex) { + this.parsedValue = new _AuthorityKeyIdentifier.default(); + this.parsedValue.parsingError = "Incorrectly formated AuthorityKeyIdentifier"; + } + + break; + + case "2.5.29.36": + // PolicyConstraints + try { + this.parsedValue = new _PolicyConstraints.default({ + schema: asn1.result + }); + } catch (ex) { + this.parsedValue = new _PolicyConstraints.default(); + this.parsedValue.parsingError = "Incorrectly formated PolicyConstraints"; + } + + break; + + case "2.5.29.37": + // ExtKeyUsage + try { + this.parsedValue = new _ExtKeyUsage.default({ + schema: asn1.result + }); + } catch (ex) { + this.parsedValue = new _ExtKeyUsage.default(); + this.parsedValue.parsingError = "Incorrectly formated ExtKeyUsage"; + } + + break; + + case "2.5.29.54": + // InhibitAnyPolicy + this.parsedValue = asn1.result; // Should be just a simple INTEGER + + break; + + case "1.3.6.1.5.5.7.1.1": // AuthorityInfoAccess + + case "1.3.6.1.5.5.7.1.11": + // SubjectInfoAccess + try { + this.parsedValue = new _InfoAccess.default({ + schema: asn1.result + }); + } catch (ex) { + this.parsedValue = new _InfoAccess.default(); + this.parsedValue.parsingError = "Incorrectly formated InfoAccess"; + } + + break; + + case "1.3.6.1.4.1.11129.2.4.2": + // SignedCertificateTimestampList + try { + this.parsedValue = new _SignedCertificateTimestampList.default({ + schema: asn1.result + }); + } catch (ex) { + this.parsedValue = new _SignedCertificateTimestampList.default(); + this.parsedValue.parsingError = "Incorrectly formated SignedCertificateTimestampList"; + } + + break; + + case "1.3.6.1.4.1.311.20.2": + // szOID_ENROLL_CERTTYPE_EXTENSION - Microsoft-specific extension + this.parsedValue = asn1.result; // Used to be simple Unicode string + + break; + + case "1.3.6.1.4.1.311.21.2": + // szOID_CERTSRV_PREVIOUS_CERT_HASH - Microsoft-specific extension + this.parsedValue = asn1.result; // Used to be simple OctetString + + break; + + case "1.3.6.1.4.1.311.21.7": + // szOID_CERTIFICATE_TEMPLATE - Microsoft-specific extension + try { + this.parsedValue = new _CertificateTemplate.default({ + schema: asn1.result + }); + } catch (ex) { + this.parsedValue = new _CertificateTemplate.default(); + this.parsedValue.parsingError = "Incorrectly formated CertificateTemplate"; + } + + break; + + case "1.3.6.1.4.1.311.21.1": + // szOID_CERTSRV_CA_VERSION - Microsoft-specific extension + try { + this.parsedValue = new _CAVersion.default({ + schema: asn1.result + }); + } catch (ex) { + this.parsedValue = new _CAVersion.default(); + this.parsedValue.parsingError = "Incorrectly formated CAVersion"; + } + + break; + + case "1.3.6.1.5.5.7.1.3": + // QCStatements + try { + this.parsedValue = new _QCStatements.default({ + schema: asn1.result + }); + } catch (ex) { + this.parsedValue = new _QCStatements.default(); + this.parsedValue.parsingError = "Incorrectly formated QCStatements"; + } + + break; + + default: + } //endregion + //endregion + + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Create array for output sequence + const outputArray = []; + outputArray.push(new asn1js.ObjectIdentifier({ + value: this.extnID + })); + if (this.critical !== Extension.defaultValues("critical")) outputArray.push(new asn1js.Boolean({ + value: this.critical + })); + outputArray.push(this.extnValue); //endregion + //region Construct and return new ASN.1 schema for this object + + return new asn1js.Sequence({ + value: outputArray + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + const object = { + extnID: this.extnID, + extnValue: this.extnValue.toJSON() + }; + if (this.critical !== Extension.defaultValues("critical")) object.critical = this.critical; + + if ("parsedValue" in this) { + if ("toJSON" in this.parsedValue) object.parsedValue = this.parsedValue.toJSON(); + } + + return object; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = Extension; + +},{"./AltName.js":5,"./AuthorityKeyIdentifier.js":11,"./BasicConstraints.js":12,"./CAVersion.js":14,"./CRLDistributionPoints.js":16,"./CertificatePolicies.js":21,"./CertificateTemplate.js":24,"./ExtKeyUsage.js":37,"./GeneralNames.js":41,"./InfoAccess.js":43,"./IssuingDistributionPoint.js":45,"./NameConstraints.js":54,"./PolicyConstraints.js":71,"./PolicyMappings.js":74,"./PrivateKeyUsagePeriod.js":77,"./QCStatements.js":79,"./SignedCertificateTimestampList.js":100,"./SubjectDirectoryAttributes.js":104,"asn1js":112,"pvutils":113}],39:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _Extension = _interopRequireDefault(require("./Extension.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC5280 + */ +class Extensions { + //********************************************************************************** + + /** + * Constructor for Extensions class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {Array.} + * @desc type + */ + this.extensions = (0, _pvutils.getParametersValue)(parameters, "extensions", Extensions.defaultValues("extensions")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "extensions": + return []; + + default: + throw new Error(`Invalid member name for Extensions class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @param {boolean} optional Flag that current schema should be optional + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}, optional = false) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [extensions] + * @property {string} [extension] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + optional, + name: names.blockName || "", + value: [new asn1js.Repeated({ + name: names.extensions || "", + value: _Extension.default.schema(names.extension || {}) + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["extensions"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, Extensions.schema({ + names: { + extensions: "extensions" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for Extensions"); //endregion + //region Get internal properties from parsed schema + + this.extensions = Array.from(asn1.result.extensions, element => new _Extension.default({ + schema: element + })); //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Construct and return new ASN.1 schema for this object + return new asn1js.Sequence({ + value: Array.from(this.extensions, element => element.toSchema()) + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + return { + extensions: Array.from(this.extensions, element => element.toJSON()) + }; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = Extensions; + +},{"./Extension.js":38,"asn1js":112,"pvutils":113}],40:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _RelativeDistinguishedNames = _interopRequireDefault(require("./RelativeDistinguishedNames.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** +//region Additional asn1js schema elements existing inside GeneralName schema +//************************************************************************************** + +/** + * Schema for "builtInStandardAttributes" of "ORAddress" + * @param {Object} parameters + * @property {Object} [names] + * @param {boolean} optional + * @returns {Sequence} + */ +function builtInStandardAttributes(parameters = {}, optional = false) { + //builtInStandardAttributes ::= Sequence { + // country-name CountryName OPTIONAL, + // administration-domain-name AdministrationDomainName OPTIONAL, + // network-address [0] IMPLICIT NetworkAddress OPTIONAL, + // terminal-identifier [1] IMPLICIT TerminalIdentifier OPTIONAL, + // private-domain-name [2] PrivateDomainName OPTIONAL, + // organization-name [3] IMPLICIT OrganizationName OPTIONAL, + // numeric-user-identifier [4] IMPLICIT NumericUserIdentifier OPTIONAL, + // personal-name [5] IMPLICIT PersonalName OPTIONAL, + // organizational-unit-names [6] IMPLICIT OrganizationalUnitNames OPTIONAL } + + /** + * @type {Object} + * @property {string} [country_name] + * @property {string} [administration_domain_name] + * @property {string} [network_address] + * @property {string} [terminal_identifier] + * @property {string} [private_domain_name] + * @property {string} [organization_name] + * @property {string} [numeric_user_identifier] + * @property {string} [personal_name] + * @property {string} [organizational_unit_names] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + optional, + value: [new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 2, + // APPLICATION-SPECIFIC + tagNumber: 1 // [1] + + }, + name: names.country_name || "", + value: [new asn1js.Choice({ + value: [new asn1js.NumericString(), new asn1js.PrintableString()] + })] + }), new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 2, + // APPLICATION-SPECIFIC + tagNumber: 2 // [2] + + }, + name: names.administration_domain_name || "", + value: [new asn1js.Choice({ + value: [new asn1js.NumericString(), new asn1js.PrintableString()] + })] + }), new asn1js.Primitive({ + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + name: names.network_address || "", + isHexOnly: true + }), new asn1js.Primitive({ + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + + }, + name: names.terminal_identifier || "", + isHexOnly: true + }), new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 2 // [2] + + }, + name: names.private_domain_name || "", + value: [new asn1js.Choice({ + value: [new asn1js.NumericString(), new asn1js.PrintableString()] + })] + }), new asn1js.Primitive({ + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 3 // [3] + + }, + name: names.organization_name || "", + isHexOnly: true + }), new asn1js.Primitive({ + optional: true, + name: names.numeric_user_identifier || "", + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 4 // [4] + + }, + isHexOnly: true + }), new asn1js.Constructed({ + optional: true, + name: names.personal_name || "", + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 5 // [5] + + }, + value: [new asn1js.Primitive({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + isHexOnly: true + }), new asn1js.Primitive({ + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + + }, + isHexOnly: true + }), new asn1js.Primitive({ + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 2 // [2] + + }, + isHexOnly: true + }), new asn1js.Primitive({ + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 3 // [3] + + }, + isHexOnly: true + })] + }), new asn1js.Constructed({ + optional: true, + name: names.organizational_unit_names || "", + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 6 // [6] + + }, + value: [new asn1js.Repeated({ + value: new asn1js.PrintableString() + })] + })] + }); +} //************************************************************************************** + +/** + * Schema for "builtInDomainDefinedAttributes" of "ORAddress" + * @param {boolean} optional + * @returns {Sequence} + */ + + +function builtInDomainDefinedAttributes(optional = false) { + return new asn1js.Sequence({ + optional, + value: [new asn1js.PrintableString(), new asn1js.PrintableString()] + }); +} //************************************************************************************** + +/** + * Schema for "builtInDomainDefinedAttributes" of "ORAddress" + * @param {boolean} optional + * @returns {Set} + */ + + +function extensionAttributes(optional = false) { + return new asn1js.Set({ + optional, + value: [new asn1js.Primitive({ + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + isHexOnly: true + }), new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + + }, + value: [new asn1js.Any()] + })] + }); +} //************************************************************************************** +//endregion +//************************************************************************************** + +/** + * Class from RFC5280 + */ + + +class GeneralName { + //********************************************************************************** + + /** + * Constructor for GeneralName class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + * @property {number} [type] value type - from a tagged value (0 for "otherName", 1 for "rfc822Name" etc.) + * @property {Object} [value] asn1js object having GeneralName value (type depends on "type" value) + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {number} + * @desc value type - from a tagged value (0 for "otherName", 1 for "rfc822Name" etc.) + */ + this.type = (0, _pvutils.getParametersValue)(parameters, "type", GeneralName.defaultValues("type")); + /** + * @type {Object} + * @desc asn1js object having GeneralName value (type depends on "type" value) + */ + + this.value = (0, _pvutils.getParametersValue)(parameters, "value", GeneralName.defaultValues("value")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "type": + return 9; + + case "value": + return {}; + + default: + throw new Error(`Invalid member name for GeneralName class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + + + static compareWithDefault(memberName, memberValue) { + switch (memberName) { + case "type": + return memberValue === GeneralName.defaultValues(memberName); + + case "value": + return Object.keys(memberValue).length === 0; + + default: + throw new Error(`Invalid member name for GeneralName class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * GeneralName ::= Choice { + * otherName [0] OtherName, + * rfc822Name [1] IA5String, + * dNSName [2] IA5String, + * x400Address [3] ORAddress, + * directoryName [4] value, + * ediPartyName [5] EDIPartyName, + * uniformResourceIdentifier [6] IA5String, + * iPAddress [7] OCTET STRING, + * registeredID [8] OBJECT IDENTIFIER } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {Object} [directoryName] + * @property {Object} [builtInStandardAttributes] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Choice({ + value: [new asn1js.Constructed({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + name: names.blockName || "", + value: [new asn1js.ObjectIdentifier(), new asn1js.Constructed({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: [new asn1js.Any()] + })] + }), new asn1js.Primitive({ + name: names.blockName || "", + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + + } + }), new asn1js.Primitive({ + name: names.blockName || "", + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 2 // [2] + + } + }), new asn1js.Constructed({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 3 // [3] + + }, + name: names.blockName || "", + value: [builtInStandardAttributes(names.builtInStandardAttributes || {}, false), builtInDomainDefinedAttributes(true), extensionAttributes(true)] + }), new asn1js.Constructed({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 4 // [4] + + }, + name: names.blockName || "", + value: [_RelativeDistinguishedNames.default.schema(names.directoryName || {})] + }), new asn1js.Constructed({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 5 // [5] + + }, + name: names.blockName || "", + value: [new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: [new asn1js.Choice({ + value: [new asn1js.TeletexString(), new asn1js.PrintableString(), new asn1js.UniversalString(), new asn1js.Utf8String(), new asn1js.BmpString()] + })] + }), new asn1js.Constructed({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + + }, + value: [new asn1js.Choice({ + value: [new asn1js.TeletexString(), new asn1js.PrintableString(), new asn1js.UniversalString(), new asn1js.Utf8String(), new asn1js.BmpString()] + })] + })] + }), new asn1js.Primitive({ + name: names.blockName || "", + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 6 // [6] + + } + }), new asn1js.Primitive({ + name: names.blockName || "", + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 7 // [7] + + } + }), new asn1js.Primitive({ + name: names.blockName || "", + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 8 // [8] + + } + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["blockName", "otherName", "rfc822Name", "dNSName", "x400Address", "directoryName", "ediPartyName", "uniformResourceIdentifier", "iPAddress", "registeredID"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, GeneralName.schema({ + names: { + blockName: "blockName", + otherName: "otherName", + rfc822Name: "rfc822Name", + dNSName: "dNSName", + x400Address: "x400Address", + directoryName: { + names: { + blockName: "directoryName" + } + }, + ediPartyName: "ediPartyName", + uniformResourceIdentifier: "uniformResourceIdentifier", + iPAddress: "iPAddress", + registeredID: "registeredID" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for GeneralName"); //endregion + //region Get internal properties from parsed schema + + this.type = asn1.result.blockName.idBlock.tagNumber; + + switch (this.type) { + case 0: + // otherName + this.value = asn1.result.blockName; + break; + + case 1: // rfc822Name + dNSName + uniformResourceIdentifier + + case 2: + case 6: + { + const value = asn1.result.blockName; + value.idBlock.tagClass = 1; // UNIVERSAL + + value.idBlock.tagNumber = 22; // IA5STRING + + const valueBER = value.toBER(false); + this.value = asn1js.fromBER(valueBER).result.valueBlock.value; + } + break; + + case 3: + // x400Address + this.value = asn1.result.blockName; + break; + + case 4: + // directoryName + this.value = new _RelativeDistinguishedNames.default({ + schema: asn1.result.directoryName + }); + break; + + case 5: + // ediPartyName + this.value = asn1.result.ediPartyName; + break; + + case 7: + // iPAddress + this.value = new asn1js.OctetString({ + valueHex: asn1.result.blockName.valueBlock.valueHex + }); + break; + + case 8: + // registeredID + { + const value = asn1.result.blockName; + value.idBlock.tagClass = 1; // UNIVERSAL + + value.idBlock.tagNumber = 6; // ObjectIdentifier + + const valueBER = value.toBER(false); + this.value = asn1js.fromBER(valueBER).result.valueBlock.toString(); // Getting a string representation of the ObjectIdentifier + } + break; + + default: + } //endregion + + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Construct and return new ASN.1 schema for this object + switch (this.type) { + case 0: + case 3: + case 5: + return new asn1js.Constructed({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: this.type + }, + value: [this.value] + }); + + case 1: + case 2: + case 6: + { + const value = new asn1js.IA5String({ + value: this.value + }); + value.idBlock.tagClass = 3; + value.idBlock.tagNumber = this.type; + return value; + } + + case 4: + return new asn1js.Constructed({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 4 + }, + value: [this.value.toSchema()] + }); + + case 7: + { + const value = this.value; + value.idBlock.tagClass = 3; + value.idBlock.tagNumber = this.type; + return value; + } + + case 8: + { + const value = new asn1js.ObjectIdentifier({ + value: this.value + }); + value.idBlock.tagClass = 3; + value.idBlock.tagNumber = this.type; + return value; + } + + default: + return GeneralName.schema(); + } //endregion + + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + const _object = { + type: this.type, + value: "" + }; + if (typeof this.value === "string") _object.value = this.value;else { + try { + _object.value = this.value.toJSON(); + } catch (ex) {} + } + return _object; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = GeneralName; + +},{"./RelativeDistinguishedNames.js":89,"asn1js":112,"pvutils":113}],41:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _GeneralName = _interopRequireDefault(require("./GeneralName.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC5280 + */ +class GeneralNames { + //********************************************************************************** + + /** + * Constructor for GeneralNames class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {Array.} + * @desc Array of "general names" + */ + this.names = (0, _pvutils.getParametersValue)(parameters, "names", GeneralNames.defaultValues("names")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "names": + return []; + + default: + throw new Error(`Invalid member name for GeneralNames class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @param {boolean} [optional=false] Flag would be element optional or not + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}, optional = false) { + /** + * @type {Object} + * @property {string} utcTimeName Name for "utcTimeName" choice + * @property {string} generalTimeName Name for "generalTimeName" choice + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + optional, + name: names.blockName || "", + value: [new asn1js.Repeated({ + name: names.generalNames || "", + value: _GeneralName.default.schema() + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["names", "generalNames"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, GeneralNames.schema({ + names: { + blockName: "names", + generalNames: "generalNames" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for GeneralNames"); //endregion + //region Get internal properties from parsed schema + + this.names = Array.from(asn1.result.generalNames, element => new _GeneralName.default({ + schema: element + })); //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Construct and return new ASN.1 schema for this object + return new asn1js.Sequence({ + value: Array.from(this.names, element => element.toSchema()) + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + return { + names: Array.from(this.names, element => element.toJSON()) + }; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = GeneralNames; + +},{"./GeneralName.js":40,"asn1js":112,"pvutils":113}],42:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _GeneralName = _interopRequireDefault(require("./GeneralName.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC5280 + */ +class GeneralSubtree { + //********************************************************************************** + + /** + * Constructor for GeneralSubtree class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {GeneralName} + * @desc base + */ + this.base = (0, _pvutils.getParametersValue)(parameters, "base", GeneralSubtree.defaultValues("base")); + /** + * @type {number|Integer} + * @desc base + */ + + this.minimum = (0, _pvutils.getParametersValue)(parameters, "minimum", GeneralSubtree.defaultValues("minimum")); + if ("maximum" in parameters) + /** + * @type {number|Integer} + * @desc minimum + */ + this.maximum = (0, _pvutils.getParametersValue)(parameters, "maximum", GeneralSubtree.defaultValues("maximum")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "base": + return new _GeneralName.default(); + + case "minimum": + return 0; + + case "maximum": + return 0; + + default: + throw new Error(`Invalid member name for GeneralSubtree class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * GeneralSubtree ::= SEQUENCE { + * base GeneralName, + * minimum [0] BaseDistance DEFAULT 0, + * maximum [1] BaseDistance OPTIONAL } + * + * BaseDistance ::= INTEGER (0..MAX) + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [base] + * @property {string} [minimum] + * @property {string} [maximum] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [_GeneralName.default.schema(names.base || {}), new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: [new asn1js.Integer({ + name: names.minimum || "" + })] + }), new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + + }, + value: [new asn1js.Integer({ + name: names.maximum || "" + })] + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["base", "minimum", "maximum"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, GeneralSubtree.schema({ + names: { + base: { + names: { + blockName: "base" + } + }, + minimum: "minimum", + maximum: "maximum" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for GeneralSubtree"); //endregion + //region Get internal properties from parsed schema + + this.base = new _GeneralName.default({ + schema: asn1.result.base + }); + + if ("minimum" in asn1.result) { + if (asn1.result.minimum.valueBlock.isHexOnly) this.minimum = asn1.result.minimum;else this.minimum = asn1.result.minimum.valueBlock.valueDec; + } + + if ("maximum" in asn1.result) { + if (asn1.result.maximum.valueBlock.isHexOnly) this.maximum = asn1.result.maximum;else this.maximum = asn1.result.maximum.valueBlock.valueDec; + } //endregion + + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Create array for output sequence + const outputArray = []; + outputArray.push(this.base.toSchema()); + + if (this.minimum !== 0) { + let valueMinimum = 0; + if (this.minimum instanceof asn1js.Integer) valueMinimum = this.minimum;else valueMinimum = new asn1js.Integer({ + value: this.minimum + }); + outputArray.push(new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: [valueMinimum] + })); + } + + if ("maximum" in this) { + let valueMaximum = 0; + if (this.maximum instanceof asn1js.Integer) valueMaximum = this.maximum;else valueMaximum = new asn1js.Integer({ + value: this.maximum + }); + outputArray.push(new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + + }, + value: [valueMaximum] + })); + } //endregion + //region Construct and return new ASN.1 schema for this object + + + return new asn1js.Sequence({ + value: outputArray + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + const object = { + base: this.base.toJSON() + }; + + if (this.minimum !== 0) { + if (typeof this.minimum === "number") object.minimum = this.minimum;else object.minimum = this.minimum.toJSON(); + } + + if ("maximum" in this) { + if (typeof this.maximum === "number") object.maximum = this.maximum;else object.maximum = this.maximum.toJSON(); + } + + return object; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = GeneralSubtree; + +},{"./GeneralName.js":40,"asn1js":112,"pvutils":113}],43:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _AccessDescription = _interopRequireDefault(require("./AccessDescription.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC5280 + */ +class InfoAccess { + //********************************************************************************** + + /** + * Constructor for InfoAccess class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {Array.} + * @desc accessDescriptions + */ + this.accessDescriptions = (0, _pvutils.getParametersValue)(parameters, "accessDescriptions", InfoAccess.defaultValues("accessDescriptions")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "accessDescriptions": + return []; + + default: + throw new Error(`Invalid member name for InfoAccess class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * AuthorityInfoAccessSyntax ::= + * SEQUENCE SIZE (1..MAX) OF AccessDescription + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [accessDescriptions] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [new asn1js.Repeated({ + name: names.accessDescriptions || "", + value: _AccessDescription.default.schema() + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["accessDescriptions"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, InfoAccess.schema({ + names: { + accessDescriptions: "accessDescriptions" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for InfoAccess"); //endregion + //region Get internal properties from parsed schema + + this.accessDescriptions = Array.from(asn1.result.accessDescriptions, element => new _AccessDescription.default({ + schema: element + })); //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Construct and return new ASN.1 schema for this object + return new asn1js.Sequence({ + value: Array.from(this.accessDescriptions, element => element.toSchema()) + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + return { + accessDescriptions: Array.from(this.accessDescriptions, element => element.toJSON()) + }; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = InfoAccess; + +},{"./AccessDescription.js":2,"asn1js":112,"pvutils":113}],44:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _RelativeDistinguishedNames = _interopRequireDefault(require("./RelativeDistinguishedNames.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC5652 + */ +class IssuerAndSerialNumber { + //********************************************************************************** + + /** + * Constructor for IssuerAndSerialNumber class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {RelativeDistinguishedNames} + * @desc issuer + */ + this.issuer = (0, _pvutils.getParametersValue)(parameters, "issuer", IssuerAndSerialNumber.defaultValues("issuer")); + /** + * @type {Integer} + * @desc serialNumber + */ + + this.serialNumber = (0, _pvutils.getParametersValue)(parameters, "serialNumber", IssuerAndSerialNumber.defaultValues("serialNumber")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "issuer": + return new _RelativeDistinguishedNames.default(); + + case "serialNumber": + return new asn1js.Integer(); + + default: + throw new Error(`Invalid member name for IssuerAndSerialNumber class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * IssuerAndSerialNumber ::= SEQUENCE { + * issuer Name, + * serialNumber CertificateSerialNumber } + * + * CertificateSerialNumber ::= INTEGER + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [issuer] + * @property {string} [serialNumber] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [_RelativeDistinguishedNames.default.schema(names.issuer || {}), new asn1js.Integer({ + name: names.serialNumber || "" + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["issuer", "serialNumber"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, IssuerAndSerialNumber.schema({ + names: { + issuer: { + names: { + blockName: "issuer" + } + }, + serialNumber: "serialNumber" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for IssuerAndSerialNumber"); //endregion + //region Get internal properties from parsed schema + + this.issuer = new _RelativeDistinguishedNames.default({ + schema: asn1.result.issuer + }); + this.serialNumber = asn1.result.serialNumber; //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Construct and return new ASN.1 schema for this object + return new asn1js.Sequence({ + value: [this.issuer.toSchema(), this.serialNumber] + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + return { + issuer: this.issuer.toJSON(), + serialNumber: this.serialNumber.toJSON() + }; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = IssuerAndSerialNumber; + +},{"./RelativeDistinguishedNames.js":89,"asn1js":112,"pvutils":113}],45:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _GeneralName = _interopRequireDefault(require("./GeneralName.js")); + +var _RelativeDistinguishedNames = _interopRequireDefault(require("./RelativeDistinguishedNames.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC5280 + */ +class IssuingDistributionPoint { + //********************************************************************************** + + /** + * Constructor for IssuingDistributionPoint class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + if ("distributionPoint" in parameters) + /** + * @type {Array.|RelativeDistinguishedNames} + * @desc distributionPoint + */ + this.distributionPoint = (0, _pvutils.getParametersValue)(parameters, "distributionPoint", IssuingDistributionPoint.defaultValues("distributionPoint")); + /** + * @type {boolean} + * @desc onlyContainsUserCerts + */ + + this.onlyContainsUserCerts = (0, _pvutils.getParametersValue)(parameters, "onlyContainsUserCerts", IssuingDistributionPoint.defaultValues("onlyContainsUserCerts")); + /** + * @type {boolean} + * @desc onlyContainsCACerts + */ + + this.onlyContainsCACerts = (0, _pvutils.getParametersValue)(parameters, "onlyContainsCACerts", IssuingDistributionPoint.defaultValues("onlyContainsCACerts")); + if ("onlySomeReasons" in parameters) + /** + * @type {number} + * @desc onlySomeReasons + */ + this.onlySomeReasons = (0, _pvutils.getParametersValue)(parameters, "onlySomeReasons", IssuingDistributionPoint.defaultValues("onlySomeReasons")); + /** + * @type {boolean} + * @desc indirectCRL + */ + + this.indirectCRL = (0, _pvutils.getParametersValue)(parameters, "indirectCRL", IssuingDistributionPoint.defaultValues("indirectCRL")); + /** + * @type {boolean} + * @desc onlyContainsAttributeCerts + */ + + this.onlyContainsAttributeCerts = (0, _pvutils.getParametersValue)(parameters, "onlyContainsAttributeCerts", IssuingDistributionPoint.defaultValues("onlyContainsAttributeCerts")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "distributionPoint": + return []; + + case "onlyContainsUserCerts": + return false; + + case "onlyContainsCACerts": + return false; + + case "onlySomeReasons": + return 0; + + case "indirectCRL": + return false; + + case "onlyContainsAttributeCerts": + return false; + + default: + throw new Error(`Invalid member name for IssuingDistributionPoint class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * IssuingDistributionPoint ::= SEQUENCE { + * distributionPoint [0] DistributionPointName OPTIONAL, + * onlyContainsUserCerts [1] BOOLEAN DEFAULT FALSE, + * onlyContainsCACerts [2] BOOLEAN DEFAULT FALSE, + * onlySomeReasons [3] ReasonFlags OPTIONAL, + * indirectCRL [4] BOOLEAN DEFAULT FALSE, + * onlyContainsAttributeCerts [5] BOOLEAN DEFAULT FALSE } + * + * ReasonFlags ::= BIT STRING { + * unused (0), + * keyCompromise (1), + * cACompromise (2), + * affiliationChanged (3), + * superseded (4), + * cessationOfOperation (5), + * certificateHold (6), + * privilegeWithdrawn (7), + * aACompromise (8) } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [distributionPoint] + * @property {string} [distributionPointNames] + * @property {string} [onlyContainsUserCerts] + * @property {string} [onlyContainsCACerts] + * @property {string} [onlySomeReasons] + * @property {string} [indirectCRL] + * @property {string} [onlyContainsAttributeCerts] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: [new asn1js.Choice({ + value: [new asn1js.Constructed({ + name: names.distributionPoint || "", + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: [new asn1js.Repeated({ + name: names.distributionPointNames || "", + value: _GeneralName.default.schema() + })] + }), new asn1js.Constructed({ + name: names.distributionPoint || "", + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + + }, + value: _RelativeDistinguishedNames.default.schema().valueBlock.value + })] + })] + }), new asn1js.Primitive({ + name: names.onlyContainsUserCerts || "", + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + + } + }), // IMPLICIT boolean value + new asn1js.Primitive({ + name: names.onlyContainsCACerts || "", + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 2 // [2] + + } + }), // IMPLICIT boolean value + new asn1js.Primitive({ + name: names.onlySomeReasons || "", + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 3 // [3] + + } + }), // IMPLICIT bitstring value + new asn1js.Primitive({ + name: names.indirectCRL || "", + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 4 // [4] + + } + }), // IMPLICIT boolean value + new asn1js.Primitive({ + name: names.onlyContainsAttributeCerts || "", + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 5 // [5] + + } + }) // IMPLICIT boolean value + ] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["distributionPoint", "distributionPointNames", "onlyContainsUserCerts", "onlyContainsCACerts", "onlySomeReasons", "indirectCRL", "onlyContainsAttributeCerts"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, IssuingDistributionPoint.schema({ + names: { + distributionPoint: "distributionPoint", + distributionPointNames: "distributionPointNames", + onlyContainsUserCerts: "onlyContainsUserCerts", + onlyContainsCACerts: "onlyContainsCACerts", + onlySomeReasons: "onlySomeReasons", + indirectCRL: "indirectCRL", + onlyContainsAttributeCerts: "onlyContainsAttributeCerts" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for IssuingDistributionPoint"); //endregion + //region Get internal properties from parsed schema + + if ("distributionPoint" in asn1.result) { + switch (true) { + case asn1.result.distributionPoint.idBlock.tagNumber === 0: + // GENERAL_NAMES variant + this.distributionPoint = Array.from(asn1.result.distributionPointNames, element => new _GeneralName.default({ + schema: element + })); + break; + + case asn1.result.distributionPoint.idBlock.tagNumber === 1: + // RDN variant + { + this.distributionPoint = new _RelativeDistinguishedNames.default({ + schema: new asn1js.Sequence({ + value: asn1.result.distributionPoint.valueBlock.value + }) + }); + } + break; + + default: + throw new Error("Unknown tagNumber for distributionPoint: {$asn1.result.distributionPoint.idBlock.tagNumber}"); + } + } + + if ("onlyContainsUserCerts" in asn1.result) { + const view = new Uint8Array(asn1.result.onlyContainsUserCerts.valueBlock.valueHex); + this.onlyContainsUserCerts = view[0] !== 0x00; + } + + if ("onlyContainsCACerts" in asn1.result) { + const view = new Uint8Array(asn1.result.onlyContainsCACerts.valueBlock.valueHex); + this.onlyContainsCACerts = view[0] !== 0x00; + } + + if ("onlySomeReasons" in asn1.result) { + const view = new Uint8Array(asn1.result.onlySomeReasons.valueBlock.valueHex); + this.onlySomeReasons = view[0]; + } + + if ("indirectCRL" in asn1.result) { + const view = new Uint8Array(asn1.result.indirectCRL.valueBlock.valueHex); + this.indirectCRL = view[0] !== 0x00; + } + + if ("onlyContainsAttributeCerts" in asn1.result) { + const view = new Uint8Array(asn1.result.onlyContainsAttributeCerts.valueBlock.valueHex); + this.onlyContainsAttributeCerts = view[0] !== 0x00; + } //endregion + + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Create array for output sequence + const outputArray = []; + + if ("distributionPoint" in this) { + let value; + + if (this.distributionPoint instanceof Array) { + value = new asn1js.Constructed({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: Array.from(this.distributionPoint, element => element.toSchema()) + }); + } else { + value = this.distributionPoint.toSchema(); + value.idBlock.tagClass = 3; // CONTEXT - SPECIFIC + + value.idBlock.tagNumber = 1; // [1] + } + + outputArray.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: [value] + })); + } + + if (this.onlyContainsUserCerts !== IssuingDistributionPoint.defaultValues("onlyContainsUserCerts")) { + outputArray.push(new asn1js.Primitive({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + + }, + valueHex: new Uint8Array([0xFF]).buffer + })); + } + + if (this.onlyContainsCACerts !== IssuingDistributionPoint.defaultValues("onlyContainsCACerts")) { + outputArray.push(new asn1js.Primitive({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 2 // [2] + + }, + valueHex: new Uint8Array([0xFF]).buffer + })); + } + + if ("onlySomeReasons" in this) { + const buffer = new ArrayBuffer(1); + const view = new Uint8Array(buffer); + view[0] = this.onlySomeReasons; + outputArray.push(new asn1js.Primitive({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 3 // [3] + + }, + valueHex: buffer + })); + } + + if (this.indirectCRL !== IssuingDistributionPoint.defaultValues("indirectCRL")) { + outputArray.push(new asn1js.Primitive({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 4 // [4] + + }, + valueHex: new Uint8Array([0xFF]).buffer + })); + } + + if (this.onlyContainsAttributeCerts !== IssuingDistributionPoint.defaultValues("onlyContainsAttributeCerts")) { + outputArray.push(new asn1js.Primitive({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 5 // [5] + + }, + valueHex: new Uint8Array([0xFF]).buffer + })); + } //endregion + //region Construct and return new ASN.1 schema for this object + + + return new asn1js.Sequence({ + value: outputArray + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + const object = {}; + + if ("distributionPoint" in this) { + if (this.distributionPoint instanceof Array) object.distributionPoint = Array.from(this.distributionPoint, element => element.toJSON());else object.distributionPoint = this.distributionPoint.toJSON(); + } + + if (this.onlyContainsUserCerts !== IssuingDistributionPoint.defaultValues("onlyContainsUserCerts")) object.onlyContainsUserCerts = this.onlyContainsUserCerts; + if (this.onlyContainsCACerts !== IssuingDistributionPoint.defaultValues("onlyContainsCACerts")) object.onlyContainsCACerts = this.onlyContainsCACerts; + if ("onlySomeReasons" in this) object.onlySomeReasons = this.onlySomeReasons; + if (this.indirectCRL !== IssuingDistributionPoint.defaultValues("indirectCRL")) object.indirectCRL = this.indirectCRL; + if (this.onlyContainsAttributeCerts !== IssuingDistributionPoint.defaultValues("onlyContainsAttributeCerts")) object.onlyContainsAttributeCerts = this.onlyContainsAttributeCerts; + return object; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = IssuingDistributionPoint; + +},{"./GeneralName.js":40,"./RelativeDistinguishedNames.js":89,"asn1js":112,"pvutils":113}],46:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _OtherKeyAttribute = _interopRequireDefault(require("./OtherKeyAttribute.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC5652 + */ +class KEKIdentifier { + //********************************************************************************** + + /** + * Constructor for KEKIdentifier class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {OctetString} + * @desc keyIdentifier + */ + this.keyIdentifier = (0, _pvutils.getParametersValue)(parameters, "keyIdentifier", KEKIdentifier.defaultValues("keyIdentifier")); + if ("date" in parameters) + /** + * @type {GeneralizedTime} + * @desc date + */ + this.date = (0, _pvutils.getParametersValue)(parameters, "date", KEKIdentifier.defaultValues("date")); + if ("other" in parameters) + /** + * @type {OtherKeyAttribute} + * @desc other + */ + this.other = (0, _pvutils.getParametersValue)(parameters, "other", KEKIdentifier.defaultValues("other")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "keyIdentifier": + return new asn1js.OctetString(); + + case "date": + return new asn1js.GeneralizedTime(); + + case "other": + return new _OtherKeyAttribute.default(); + + default: + throw new Error(`Invalid member name for KEKIdentifier class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + + + static compareWithDefault(memberName, memberValue) { + switch (memberName) { + case "keyIdentifier": + return memberValue.isEqual(KEKIdentifier.defaultValues("keyIdentifier")); + + case "date": + // noinspection OverlyComplexBooleanExpressionJS + return memberValue.year === 0 && memberValue.month === 0 && memberValue.day === 0 && memberValue.hour === 0 && memberValue.minute === 0 && memberValue.second === 0 && memberValue.millisecond === 0; + + case "other": + return memberValue.compareWithDefault("keyAttrId", memberValue.keyAttrId) && "keyAttr" in memberValue === false; + + default: + throw new Error(`Invalid member name for KEKIdentifier class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * KEKIdentifier ::= SEQUENCE { + * keyIdentifier OCTET STRING, + * date GeneralizedTime OPTIONAL, + * other OtherKeyAttribute OPTIONAL } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [keyIdentifier] + * @property {string} [date] + * @property {string} [other] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [new asn1js.OctetString({ + name: names.keyIdentifier || "" + }), new asn1js.GeneralizedTime({ + optional: true, + name: names.date || "" + }), _OtherKeyAttribute.default.schema(names.other || {})] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["keyIdentifier", "date", "other"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, KEKIdentifier.schema({ + names: { + keyIdentifier: "keyIdentifier", + date: "date", + other: { + names: { + blockName: "other" + } + } + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for KEKIdentifier"); //endregion + //region Get internal properties from parsed schema + + this.keyIdentifier = asn1.result.keyIdentifier; + if ("date" in asn1.result) this.date = asn1.result.date; + if ("other" in asn1.result) this.other = new _OtherKeyAttribute.default({ + schema: asn1.result.other + }); //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Create array for output sequence + const outputArray = []; + outputArray.push(this.keyIdentifier); + if ("date" in this) outputArray.push(this.date); + if ("other" in this) outputArray.push(this.other.toSchema()); //endregion + //region Construct and return new ASN.1 schema for this object + + return new asn1js.Sequence({ + value: outputArray + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + const _object = { + keyIdentifier: this.keyIdentifier.toJSON() + }; + if ("date" in this) _object.date = this.date; + if ("other" in this) _object.other = this.other.toJSON(); + return _object; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = KEKIdentifier; + +},{"./OtherKeyAttribute.js":61,"asn1js":112,"pvutils":113}],47:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _KEKIdentifier = _interopRequireDefault(require("./KEKIdentifier.js")); + +var _AlgorithmIdentifier = _interopRequireDefault(require("./AlgorithmIdentifier.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC5652 + */ +class KEKRecipientInfo { + //********************************************************************************** + + /** + * Constructor for KEKRecipientInfo class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {number} + * @desc version + */ + this.version = (0, _pvutils.getParametersValue)(parameters, "version", KEKRecipientInfo.defaultValues("version")); + /** + * @type {KEKIdentifier} + * @desc kekid + */ + + this.kekid = (0, _pvutils.getParametersValue)(parameters, "kekid", KEKRecipientInfo.defaultValues("kekid")); + /** + * @type {AlgorithmIdentifier} + * @desc keyEncryptionAlgorithm + */ + + this.keyEncryptionAlgorithm = (0, _pvutils.getParametersValue)(parameters, "keyEncryptionAlgorithm", KEKRecipientInfo.defaultValues("keyEncryptionAlgorithm")); + /** + * @type {OctetString} + * @desc encryptedKey + */ + + this.encryptedKey = (0, _pvutils.getParametersValue)(parameters, "encryptedKey", KEKRecipientInfo.defaultValues("encryptedKey")); + /** + * @type {ArrayBuffer} + * @desc preDefinedKEK KEK using to encrypt CEK + */ + + this.preDefinedKEK = (0, _pvutils.getParametersValue)(parameters, "preDefinedKEK", KEKRecipientInfo.defaultValues("preDefinedKEK")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "version": + return 0; + + case "kekid": + return new _KEKIdentifier.default(); + + case "keyEncryptionAlgorithm": + return new _AlgorithmIdentifier.default(); + + case "encryptedKey": + return new asn1js.OctetString(); + + case "preDefinedKEK": + return new ArrayBuffer(0); + + default: + throw new Error(`Invalid member name for KEKRecipientInfo class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + + + static compareWithDefault(memberName, memberValue) { + switch (memberName) { + case "KEKRecipientInfo": + return memberValue === KEKRecipientInfo.defaultValues("version"); + + case "kekid": + return memberValue.compareWithDefault("keyIdentifier", memberValue.keyIdentifier) && "date" in memberValue === false && "other" in memberValue === false; + + case "keyEncryptionAlgorithm": + return memberValue.algorithmId === "" && "algorithmParams" in memberValue === false; + + case "encryptedKey": + return memberValue.isEqual(KEKRecipientInfo.defaultValues("encryptedKey")); + + case "preDefinedKEK": + return memberValue.byteLength === 0; + + default: + throw new Error(`Invalid member name for KEKRecipientInfo class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * KEKRecipientInfo ::= SEQUENCE { + * version CMSVersion, -- always set to 4 + * kekid KEKIdentifier, + * keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier, + * encryptedKey EncryptedKey } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [version] + * @property {string} [kekid] + * @property {string} [keyEncryptionAlgorithm] + * @property {string} [encryptedKey] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [new asn1js.Integer({ + name: names.version || "" + }), _KEKIdentifier.default.schema(names.kekid || {}), _AlgorithmIdentifier.default.schema(names.keyEncryptionAlgorithm || {}), new asn1js.OctetString({ + name: names.encryptedKey || "" + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["version", "kekid", "keyEncryptionAlgorithm", "encryptedKey"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, KEKRecipientInfo.schema({ + names: { + version: "version", + kekid: { + names: { + blockName: "kekid" + } + }, + keyEncryptionAlgorithm: { + names: { + blockName: "keyEncryptionAlgorithm" + } + }, + encryptedKey: "encryptedKey" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for KEKRecipientInfo"); //endregion + //region Get internal properties from parsed schema + + this.version = asn1.result.version.valueBlock.valueDec; + this.kekid = new _KEKIdentifier.default({ + schema: asn1.result.kekid + }); + this.keyEncryptionAlgorithm = new _AlgorithmIdentifier.default({ + schema: asn1.result.keyEncryptionAlgorithm + }); + this.encryptedKey = asn1.result.encryptedKey; //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Construct and return new ASN.1 schema for this object + return new asn1js.Sequence({ + value: [new asn1js.Integer({ + value: this.version + }), this.kekid.toSchema(), this.keyEncryptionAlgorithm.toSchema(), this.encryptedKey] + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + return { + version: this.version, + kekid: this.kekid.toJSON(), + keyEncryptionAlgorithm: this.keyEncryptionAlgorithm.toJSON(), + encryptedKey: this.encryptedKey.toJSON() + }; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = KEKRecipientInfo; + +},{"./AlgorithmIdentifier.js":4,"./KEKIdentifier.js":46,"asn1js":112,"pvutils":113}],48:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _IssuerAndSerialNumber = _interopRequireDefault(require("./IssuerAndSerialNumber.js")); + +var _RecipientKeyIdentifier = _interopRequireDefault(require("./RecipientKeyIdentifier.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC5652 + */ +class KeyAgreeRecipientIdentifier { + //********************************************************************************** + + /** + * Constructor for KeyAgreeRecipientIdentifier class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {number} + * @desc variant + */ + this.variant = (0, _pvutils.getParametersValue)(parameters, "variant", KeyAgreeRecipientIdentifier.defaultValues("variant")); + /** + * @type {*} + * @desc values + */ + + this.value = (0, _pvutils.getParametersValue)(parameters, "value", KeyAgreeRecipientIdentifier.defaultValues("value")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "variant": + return -1; + + case "value": + return {}; + + default: + throw new Error(`Invalid member name for KeyAgreeRecipientIdentifier class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + + + static compareWithDefault(memberName, memberValue) { + switch (memberName) { + case "variant": + return memberValue === -1; + + case "value": + return Object.keys(memberValue).length === 0; + + default: + throw new Error(`Invalid member name for KeyAgreeRecipientIdentifier class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * KeyAgreeRecipientIdentifier ::= CHOICE { + * issuerAndSerialNumber IssuerAndSerialNumber, + * rKeyId [0] IMPLICIT RecipientKeyIdentifier } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [issuerAndSerialNumber] + * @property {string} [rKeyId] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Choice({ + value: [_IssuerAndSerialNumber.default.schema(names.issuerAndSerialNumber || { + names: { + blockName: names.blockName || "" + } + }), new asn1js.Constructed({ + name: names.blockName || "", + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: _RecipientKeyIdentifier.default.schema(names.rKeyId || { + names: { + blockName: names.blockName || "" + } + }).valueBlock.value + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["blockName"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, KeyAgreeRecipientIdentifier.schema({ + names: { + blockName: "blockName" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for KeyAgreeRecipientIdentifier"); //endregion + //region Get internal properties from parsed schema + + if (asn1.result.blockName.idBlock.tagClass === 1) { + this.variant = 1; + this.value = new _IssuerAndSerialNumber.default({ + schema: asn1.result.blockName + }); + } else { + this.variant = 2; + this.value = new _RecipientKeyIdentifier.default({ + schema: new asn1js.Sequence({ + value: asn1.result.blockName.valueBlock.value + }) + }); + } //endregion + + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Construct and return new ASN.1 schema for this object + switch (this.variant) { + case 1: + return this.value.toSchema(); + + case 2: + return new asn1js.Constructed({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: this.value.toSchema().valueBlock.value + }); + + default: + return new asn1js.Any(); + } //endregion + + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + const _object = { + variant: this.variant + }; + if (this.variant === 1 || this.variant === 2) _object.value = this.value.toJSON(); + return _object; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = KeyAgreeRecipientIdentifier; + +},{"./IssuerAndSerialNumber.js":44,"./RecipientKeyIdentifier.js":88,"asn1js":112,"pvutils":113}],49:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _OriginatorIdentifierOrKey = _interopRequireDefault(require("./OriginatorIdentifierOrKey.js")); + +var _AlgorithmIdentifier = _interopRequireDefault(require("./AlgorithmIdentifier.js")); + +var _RecipientEncryptedKeys = _interopRequireDefault(require("./RecipientEncryptedKeys.js")); + +var _Certificate = _interopRequireDefault(require("./Certificate.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC5652 + */ +class KeyAgreeRecipientInfo { + //********************************************************************************** + + /** + * Constructor for KeyAgreeRecipientInfo class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {number} + * @desc version + */ + this.version = (0, _pvutils.getParametersValue)(parameters, "version", KeyAgreeRecipientInfo.defaultValues("version")); + /** + * @type {OriginatorIdentifierOrKey} + * @desc originator + */ + + this.originator = (0, _pvutils.getParametersValue)(parameters, "originator", KeyAgreeRecipientInfo.defaultValues("originator")); + if ("ukm" in parameters) + /** + * @type {OctetString} + * @desc ukm + */ + this.ukm = (0, _pvutils.getParametersValue)(parameters, "ukm", KeyAgreeRecipientInfo.defaultValues("ukm")); + /** + * @type {AlgorithmIdentifier} + * @desc keyEncryptionAlgorithm + */ + + this.keyEncryptionAlgorithm = (0, _pvutils.getParametersValue)(parameters, "keyEncryptionAlgorithm", KeyAgreeRecipientInfo.defaultValues("keyEncryptionAlgorithm")); + /** + * @type {RecipientEncryptedKeys} + * @desc recipientEncryptedKeys + */ + + this.recipientEncryptedKeys = (0, _pvutils.getParametersValue)(parameters, "recipientEncryptedKeys", KeyAgreeRecipientInfo.defaultValues("recipientEncryptedKeys")); + /** + * @type {Certificate} + * @desc recipientCertificate For some reasons we need to store recipient's certificate here + */ + + this.recipientCertificate = (0, _pvutils.getParametersValue)(parameters, "recipientCertificate", KeyAgreeRecipientInfo.defaultValues("recipientCertificate")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "version": + return 0; + + case "originator": + return new _OriginatorIdentifierOrKey.default(); + + case "ukm": + return new asn1js.OctetString(); + + case "keyEncryptionAlgorithm": + return new _AlgorithmIdentifier.default(); + + case "recipientEncryptedKeys": + return new _RecipientEncryptedKeys.default(); + + case "recipientCertificate": + return new _Certificate.default(); + + default: + throw new Error(`Invalid member name for KeyAgreeRecipientInfo class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + + + static compareWithDefault(memberName, memberValue) { + switch (memberName) { + case "version": + return memberValue === 0; + + case "originator": + return memberValue.variant === -1 && "value" in memberValue === false; + + case "ukm": + return memberValue.isEqual(KeyAgreeRecipientInfo.defaultValues("ukm")); + + case "keyEncryptionAlgorithm": + return memberValue.algorithmId === "" && "algorithmParams" in memberValue === false; + + case "recipientEncryptedKeys": + return memberValue.encryptedKeys.length === 0; + + case "recipientCertificate": + return false; + // For now leave it as is + + default: + throw new Error(`Invalid member name for KeyAgreeRecipientInfo class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * KeyAgreeRecipientInfo ::= SEQUENCE { + * version CMSVersion, -- always set to 3 + * originator [0] EXPLICIT OriginatorIdentifierOrKey, + * ukm [1] EXPLICIT UserKeyingMaterial OPTIONAL, + * keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier, + * recipientEncryptedKeys RecipientEncryptedKeys } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [version] + * @property {string} [originator] + * @property {string} [ukm] + * @property {string} [keyEncryptionAlgorithm] + * @property {string} [recipientEncryptedKeys] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [new asn1js.Integer({ + name: names.version || "" + }), new asn1js.Constructed({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: [_OriginatorIdentifierOrKey.default.schema(names.originator || {})] + }), new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + + }, + value: [new asn1js.OctetString({ + name: names.ukm || "" + })] + }), _AlgorithmIdentifier.default.schema(names.keyEncryptionAlgorithm || {}), _RecipientEncryptedKeys.default.schema(names.recipientEncryptedKeys || {})] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["version", "originator", "ukm", "keyEncryptionAlgorithm", "recipientEncryptedKeys"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, KeyAgreeRecipientInfo.schema({ + names: { + version: "version", + originator: { + names: { + blockName: "originator" + } + }, + ukm: "ukm", + keyEncryptionAlgorithm: { + names: { + blockName: "keyEncryptionAlgorithm" + } + }, + recipientEncryptedKeys: { + names: { + blockName: "recipientEncryptedKeys" + } + } + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for KeyAgreeRecipientInfo"); //endregion + //region Get internal properties from parsed schema + + this.version = asn1.result.version.valueBlock.valueDec; + this.originator = new _OriginatorIdentifierOrKey.default({ + schema: asn1.result.originator + }); + if ("ukm" in asn1.result) this.ukm = asn1.result.ukm; + this.keyEncryptionAlgorithm = new _AlgorithmIdentifier.default({ + schema: asn1.result.keyEncryptionAlgorithm + }); + this.recipientEncryptedKeys = new _RecipientEncryptedKeys.default({ + schema: asn1.result.recipientEncryptedKeys + }); //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Create array for final sequence + const outputArray = []; + outputArray.push(new asn1js.Integer({ + value: this.version + })); + outputArray.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: [this.originator.toSchema()] + })); + + if ("ukm" in this) { + outputArray.push(new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + + }, + value: [this.ukm] + })); + } + + outputArray.push(this.keyEncryptionAlgorithm.toSchema()); + outputArray.push(this.recipientEncryptedKeys.toSchema()); //endregion + //region Construct and return new ASN.1 schema for this object + + return new asn1js.Sequence({ + value: outputArray + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + const _object = { + version: this.version, + originator: this.originator.toJSON() + }; + if ("ukm" in this) _object.ukm = this.ukm.toJSON(); + _object.keyEncryptionAlgorithm = this.keyEncryptionAlgorithm.toJSON(); + _object.recipientEncryptedKeys = this.recipientEncryptedKeys.toJSON(); + return _object; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = KeyAgreeRecipientInfo; + +},{"./AlgorithmIdentifier.js":4,"./Certificate.js":19,"./OriginatorIdentifierOrKey.js":57,"./RecipientEncryptedKeys.js":85,"asn1js":112,"pvutils":113}],50:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var _PrivateKeyInfo = _interopRequireDefault(require("./PrivateKeyInfo.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +//************************************************************************************** + +/** + * Class from RFC5208 + */ +class KeyBag extends _PrivateKeyInfo.default { + //********************************************************************************** + + /** + * Constructor for Attribute class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + super(parameters); + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = KeyBag; + +},{"./PrivateKeyInfo.js":76}],51:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _AlgorithmIdentifier = _interopRequireDefault(require("./AlgorithmIdentifier.js")); + +var _Certificate = _interopRequireDefault(require("./Certificate.js")); + +var _RecipientIdentifier = _interopRequireDefault(require("./RecipientIdentifier.js")); + +var _IssuerAndSerialNumber = _interopRequireDefault(require("./IssuerAndSerialNumber.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC5652 + */ +class KeyTransRecipientInfo { + //********************************************************************************** + + /** + * Constructor for KeyTransRecipientInfo class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {number} + * @desc version + */ + this.version = (0, _pvutils.getParametersValue)(parameters, "version", KeyTransRecipientInfo.defaultValues("version")); + /** + * @type {RecipientIdentifier} + * @desc rid + */ + + this.rid = (0, _pvutils.getParametersValue)(parameters, "rid", KeyTransRecipientInfo.defaultValues("rid")); + /** + * @type {AlgorithmIdentifier} + * @desc keyEncryptionAlgorithm + */ + + this.keyEncryptionAlgorithm = (0, _pvutils.getParametersValue)(parameters, "keyEncryptionAlgorithm", KeyTransRecipientInfo.defaultValues("keyEncryptionAlgorithm")); + /** + * @type {OctetString} + * @desc encryptedKey + */ + + this.encryptedKey = (0, _pvutils.getParametersValue)(parameters, "encryptedKey", KeyTransRecipientInfo.defaultValues("encryptedKey")); + /** + * @type {Certificate} + * @desc recipientCertificate For some reasons we need to store recipient's certificate here + */ + + this.recipientCertificate = (0, _pvutils.getParametersValue)(parameters, "recipientCertificate", KeyTransRecipientInfo.defaultValues("recipientCertificate")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "version": + return -1; + + case "rid": + return {}; + + case "keyEncryptionAlgorithm": + return new _AlgorithmIdentifier.default(); + + case "encryptedKey": + return new asn1js.OctetString(); + + case "recipientCertificate": + return new _Certificate.default(); + + default: + throw new Error(`Invalid member name for KeyTransRecipientInfo class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + + + static compareWithDefault(memberName, memberValue) { + switch (memberName) { + case "version": + return memberValue === KeyTransRecipientInfo.defaultValues("version"); + + case "rid": + return Object.keys(memberValue).length === 0; + + case "keyEncryptionAlgorithm": + case "encryptedKey": + return memberValue.isEqual(KeyTransRecipientInfo.defaultValues(memberName)); + + case "recipientCertificate": + return false; + // For now we do not need to compare any values with the "recipientCertificate" + + default: + throw new Error(`Invalid member name for KeyTransRecipientInfo class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * KeyTransRecipientInfo ::= SEQUENCE { + * version CMSVersion, -- always set to 0 or 2 + * rid RecipientIdentifier, + * keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier, + * encryptedKey EncryptedKey } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [version] + * @property {string} [rid] + * @property {string} [keyEncryptionAlgorithm] + * @property {string} [encryptedKey] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [new asn1js.Integer({ + name: names.version || "" + }), _RecipientIdentifier.default.schema(names.rid || {}), _AlgorithmIdentifier.default.schema(names.keyEncryptionAlgorithm || {}), new asn1js.OctetString({ + name: names.encryptedKey || "" + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["version", "rid", "keyEncryptionAlgorithm", "encryptedKey"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, KeyTransRecipientInfo.schema({ + names: { + version: "version", + rid: { + names: { + blockName: "rid" + } + }, + keyEncryptionAlgorithm: { + names: { + blockName: "keyEncryptionAlgorithm" + } + }, + encryptedKey: "encryptedKey" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for KeyTransRecipientInfo"); //endregion + //region Get internal properties from parsed schema + + this.version = asn1.result.version.valueBlock.valueDec; + if (asn1.result.rid.idBlock.tagClass === 3) this.rid = asn1.result.rid.valueBlock.value[0]; // SubjectKeyIdentifier + else this.rid = new _IssuerAndSerialNumber.default({ + schema: asn1.result.rid + }); + this.keyEncryptionAlgorithm = new _AlgorithmIdentifier.default({ + schema: asn1.result.keyEncryptionAlgorithm + }); + this.encryptedKey = asn1.result.encryptedKey; //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Create array for output sequence + const outputArray = []; + + if (this.rid instanceof _IssuerAndSerialNumber.default) { + this.version = 0; + outputArray.push(new asn1js.Integer({ + value: this.version + })); + outputArray.push(this.rid.toSchema()); + } else { + this.version = 2; + outputArray.push(new asn1js.Integer({ + value: this.version + })); + outputArray.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: [this.rid] + })); + } + + outputArray.push(this.keyEncryptionAlgorithm.toSchema()); + outputArray.push(this.encryptedKey); //endregion + //region Construct and return new ASN.1 schema for this object + + return new asn1js.Sequence({ + value: outputArray + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + return { + version: this.version, + rid: this.rid.toJSON(), + keyEncryptionAlgorithm: this.keyEncryptionAlgorithm.toJSON(), + encryptedKey: this.encryptedKey.toJSON() + }; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = KeyTransRecipientInfo; + +},{"./AlgorithmIdentifier.js":4,"./Certificate.js":19,"./IssuerAndSerialNumber.js":44,"./RecipientIdentifier.js":86,"asn1js":112,"pvutils":113}],52:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _DigestInfo = _interopRequireDefault(require("./DigestInfo.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC7292 + */ +class MacData { + //********************************************************************************** + + /** + * Constructor for MacData class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {DigestInfo} + * @desc mac + */ + this.mac = (0, _pvutils.getParametersValue)(parameters, "mac", MacData.defaultValues("mac")); + /** + * @type {OctetString} + * @desc macSalt + */ + + this.macSalt = (0, _pvutils.getParametersValue)(parameters, "macSalt", MacData.defaultValues("macSalt")); + if ("iterations" in parameters) + /** + * @type {number} + * @desc iterations + */ + this.iterations = (0, _pvutils.getParametersValue)(parameters, "iterations", MacData.defaultValues("iterations")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "mac": + return new _DigestInfo.default(); + + case "macSalt": + return new asn1js.OctetString(); + + case "iterations": + return 1; + + default: + throw new Error(`Invalid member name for MacData class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + + + static compareWithDefault(memberName, memberValue) { + switch (memberName) { + case "mac": + return _DigestInfo.default.compareWithDefault("digestAlgorithm", memberValue.digestAlgorithm) && _DigestInfo.default.compareWithDefault("digest", memberValue.digest); + + case "macSalt": + return memberValue.isEqual(MacData.defaultValues(memberName)); + + case "iterations": + return memberValue === MacData.defaultValues(memberName); + + default: + throw new Error(`Invalid member name for MacData class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * MacData ::= SEQUENCE { + * mac DigestInfo, + * macSalt OCTET STRING, + * iterations INTEGER DEFAULT 1 + * -- Note: The default is for historical reasons and its use is + * -- deprecated. A higher value, like 1024 is recommended. + * } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [optional] + * @property {string} [mac] + * @property {string} [macSalt] + * @property {string} [iterations] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + optional: names.optional || true, + value: [_DigestInfo.default.schema(names.mac || { + names: { + blockName: "mac" + } + }), new asn1js.OctetString({ + name: names.macSalt || "macSalt" + }), new asn1js.Integer({ + optional: true, + name: names.iterations || "iterations" + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["mac", "macSalt", "iterations"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, MacData.schema({ + names: { + mac: { + names: { + blockName: "mac" + } + }, + macSalt: "macSalt", + iterations: "iterations" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for MacData"); //endregion + //region Get internal properties from parsed schema + + this.mac = new _DigestInfo.default({ + schema: asn1.result.mac + }); + this.macSalt = asn1.result.macSalt; + if ("iterations" in asn1.result) this.iterations = asn1.result.iterations.valueBlock.valueDec; //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Construct and return new ASN.1 schema for this object + const outputArray = [this.mac.toSchema(), this.macSalt]; + if ("iterations" in this) outputArray.push(new asn1js.Integer({ + value: this.iterations + })); + return new asn1js.Sequence({ + value: outputArray + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + const output = { + mac: this.mac.toJSON(), + macSalt: this.macSalt.toJSON() + }; + if ("iterations" in this) output.iterations = this.iterations.toJSON(); + return output; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = MacData; + +},{"./DigestInfo.js":28,"asn1js":112,"pvutils":113}],53:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _AlgorithmIdentifier = _interopRequireDefault(require("./AlgorithmIdentifier.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC3161 + */ +class MessageImprint { + //********************************************************************************** + + /** + * Constructor for MessageImprint class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {AlgorithmIdentifier} + * @desc hashAlgorithm + */ + this.hashAlgorithm = (0, _pvutils.getParametersValue)(parameters, "hashAlgorithm", MessageImprint.defaultValues("hashAlgorithm")); + /** + * @type {OctetString} + * @desc hashedMessage + */ + + this.hashedMessage = (0, _pvutils.getParametersValue)(parameters, "hashedMessage", MessageImprint.defaultValues("hashedMessage")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "hashAlgorithm": + return new _AlgorithmIdentifier.default(); + + case "hashedMessage": + return new asn1js.OctetString(); + + default: + throw new Error(`Invalid member name for MessageImprint class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + + + static compareWithDefault(memberName, memberValue) { + switch (memberName) { + case "hashAlgorithm": + return memberValue.algorithmId === "" && "algorithmParams" in memberValue === false; + + case "hashedMessage": + return memberValue.isEqual(MessageImprint.defaultValues(memberName)) === 0; + + default: + throw new Error(`Invalid member name for MessageImprint class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * MessageImprint ::= SEQUENCE { + * hashAlgorithm AlgorithmIdentifier, + * hashedMessage OCTET STRING } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [hashAlgorithm] + * @property {string} [hashedMessage] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [_AlgorithmIdentifier.default.schema(names.hashAlgorithm || {}), new asn1js.OctetString({ + name: names.hashedMessage || "" + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["hashAlgorithm", "hashedMessage"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, MessageImprint.schema({ + names: { + hashAlgorithm: { + names: { + blockName: "hashAlgorithm" + } + }, + hashedMessage: "hashedMessage" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for MessageImprint"); //endregion + //region Get internal properties from parsed schema + + this.hashAlgorithm = new _AlgorithmIdentifier.default({ + schema: asn1.result.hashAlgorithm + }); + this.hashedMessage = asn1.result.hashedMessage; //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Construct and return new ASN.1 schema for this object + return new asn1js.Sequence({ + value: [this.hashAlgorithm.toSchema(), this.hashedMessage] + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + return { + hashAlgorithm: this.hashAlgorithm.toJSON(), + hashedMessage: this.hashedMessage.toJSON() + }; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = MessageImprint; + +},{"./AlgorithmIdentifier.js":4,"asn1js":112,"pvutils":113}],54:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _GeneralSubtree = _interopRequireDefault(require("./GeneralSubtree.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC5280 + */ +class NameConstraints { + //********************************************************************************** + + /** + * Constructor for NameConstraints class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + if ("permittedSubtrees" in parameters) + /** + * @type {Array.} + * @desc permittedSubtrees + */ + this.permittedSubtrees = (0, _pvutils.getParametersValue)(parameters, "permittedSubtrees", NameConstraints.defaultValues("permittedSubtrees")); + if ("excludedSubtrees" in parameters) + /** + * @type {Array.} + * @desc excludedSubtrees + */ + this.excludedSubtrees = (0, _pvutils.getParametersValue)(parameters, "excludedSubtrees", NameConstraints.defaultValues("excludedSubtrees")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "permittedSubtrees": + return []; + + case "excludedSubtrees": + return []; + + default: + throw new Error(`Invalid member name for NameConstraints class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * NameConstraints ::= SEQUENCE { + * permittedSubtrees [0] GeneralSubtrees OPTIONAL, + * excludedSubtrees [1] GeneralSubtrees OPTIONAL } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [permittedSubtrees] + * @property {string} [excludedSubtrees] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: [new asn1js.Repeated({ + name: names.permittedSubtrees || "", + value: _GeneralSubtree.default.schema() + })] + }), new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + + }, + value: [new asn1js.Repeated({ + name: names.excludedSubtrees || "", + value: _GeneralSubtree.default.schema() + })] + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["permittedSubtrees", "excludedSubtrees"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, NameConstraints.schema({ + names: { + permittedSubtrees: "permittedSubtrees", + excludedSubtrees: "excludedSubtrees" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for NameConstraints"); //endregion + //region Get internal properties from parsed schema + + if ("permittedSubtrees" in asn1.result) this.permittedSubtrees = Array.from(asn1.result.permittedSubtrees, element => new _GeneralSubtree.default({ + schema: element + })); + if ("excludedSubtrees" in asn1.result) this.excludedSubtrees = Array.from(asn1.result.excludedSubtrees, element => new _GeneralSubtree.default({ + schema: element + })); //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Create array for output sequence + const outputArray = []; + + if ("permittedSubtrees" in this) { + outputArray.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: Array.from(this.permittedSubtrees, element => element.toSchema()) + })); + } + + if ("excludedSubtrees" in this) { + outputArray.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + + }, + value: Array.from(this.excludedSubtrees, element => element.toSchema()) + })); + } //endregion + //region Construct and return new ASN.1 schema for this object + + + return new asn1js.Sequence({ + value: outputArray + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + const object = {}; + if ("permittedSubtrees" in this) object.permittedSubtrees = Array.from(this.permittedSubtrees, element => element.toJSON()); + if ("excludedSubtrees" in this) object.excludedSubtrees = Array.from(this.excludedSubtrees, element => element.toJSON()); + return object; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = NameConstraints; + +},{"./GeneralSubtree.js":42,"asn1js":112,"pvutils":113}],55:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _common = require("./common.js"); + +var _TBSRequest = _interopRequireDefault(require("./TBSRequest.js")); + +var _Signature = _interopRequireDefault(require("./Signature.js")); + +var _Request = _interopRequireDefault(require("./Request.js")); + +var _CertID = _interopRequireDefault(require("./CertID.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC6960 + */ +class OCSPRequest { + //********************************************************************************** + + /** + * Constructor for OCSPRequest class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {TBSRequest} + * @desc tbsRequest + */ + this.tbsRequest = (0, _pvutils.getParametersValue)(parameters, "tbsRequest", OCSPRequest.defaultValues("tbsRequest")); + if ("optionalSignature" in parameters) + /** + * @type {Signature} + * @desc optionalSignature + */ + this.optionalSignature = (0, _pvutils.getParametersValue)(parameters, "optionalSignature", OCSPRequest.defaultValues("optionalSignature")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "tbsRequest": + return new _TBSRequest.default(); + + case "optionalSignature": + return new _Signature.default(); + + default: + throw new Error(`Invalid member name for OCSPRequest class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + + + static compareWithDefault(memberName, memberValue) { + switch (memberName) { + case "tbsRequest": + // noinspection OverlyComplexBooleanExpressionJS + return _TBSRequest.default.compareWithDefault("tbs", memberValue.tbs) && _TBSRequest.default.compareWithDefault("version", memberValue.version) && _TBSRequest.default.compareWithDefault("requestorName", memberValue.requestorName) && _TBSRequest.default.compareWithDefault("requestList", memberValue.requestList) && _TBSRequest.default.compareWithDefault("requestExtensions", memberValue.requestExtensions); + + case "optionalSignature": + return _Signature.default.compareWithDefault("signatureAlgorithm", memberValue.signatureAlgorithm) && _Signature.default.compareWithDefault("signature", memberValue.signature) && _Signature.default.compareWithDefault("certs", memberValue.certs); + + default: + throw new Error(`Invalid member name for OCSPRequest class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * OCSPRequest ::= SEQUENCE { + * tbsRequest TBSRequest, + * optionalSignature [0] EXPLICIT Signature OPTIONAL } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [tbsRequest] + * @property {string} [optionalSignature] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "OCSPRequest", + value: [_TBSRequest.default.schema(names.tbsRequest || { + names: { + blockName: "tbsRequest" + } + }), new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: [_Signature.default.schema(names.optionalSignature || { + names: { + blockName: "optionalSignature" + } + })] + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["tbsRequest", "optionalSignature"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, OCSPRequest.schema()); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for OCSPRequest"); //endregion + //region Get internal properties from parsed schema + + this.tbsRequest = new _TBSRequest.default({ + schema: asn1.result.tbsRequest + }); + if ("optionalSignature" in asn1.result) this.optionalSignature = new _Signature.default({ + schema: asn1.result.optionalSignature + }); //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @param {boolean} encodeFlag If param equal to false then create TBS schema via decoding stored value. In othe case create TBS schema via assembling from TBS parts. + * @returns {Object} asn1js object + */ + + + toSchema(encodeFlag = false) { + //region Create array for output sequence + const outputArray = []; + outputArray.push(this.tbsRequest.toSchema(encodeFlag)); + if ("optionalSignature" in this) outputArray.push(this.optionalSignature.toSchema()); //endregion + //region Construct and return new ASN.1 schema for this object + + return new asn1js.Sequence({ + value: outputArray + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + const _object = { + tbsRequest: this.tbsRequest.toJSON() + }; + if ("optionalSignature" in this) _object.optionalSignature = this.optionalSignature.toJSON(); + return _object; + } //********************************************************************************** + + /** + * Making OCSP Request for specific certificate + * @param {Certificate} certificate Certificate making OCSP Request for + * @param {Object} parameters Additional parameters + * @returns {Promise} + */ + + + createForCertificate(certificate, parameters) { + //region Initial variables + let sequence = Promise.resolve(); + const certID = new _CertID.default(); //endregion + //region Create OCSP certificate identifier for the certificate + + sequence = sequence.then(() => certID.createForCertificate(certificate, parameters)); //endregion + //region Make final request data + + sequence = sequence.then(() => { + this.tbsRequest = new _TBSRequest.default({ + requestList: [new _Request.default({ + reqCert: certID + })] + }); + }, error => Promise.reject(error)); //endregion + + return sequence; + } //********************************************************************************** + + /** + * Make signature for current OCSP Request + * @param {Object} privateKey Private key for "subjectPublicKeyInfo" structure + * @param {string} [hashAlgorithm] Hashing algorithm. Default SHA-1 + * @returns {Promise} + */ + + + sign(privateKey, hashAlgorithm = "SHA-1") { + //region Initial checking + //region Check private key + if (typeof privateKey === "undefined") return Promise.reject("Need to provide a private key for signing"); //endregion + //region Check that "optionalSignature" exists in the current request + + if ("optionalSignature" in this === false) return Promise.reject("Need to create \"optionalSignature\" field before signing"); //endregion + //endregion + //region Initial variables + + let sequence = Promise.resolve(); + let parameters; + let tbs; + const engine = (0, _common.getEngine)(); //endregion + //region Get a "default parameters" for current algorithm and set correct signature algorithm + + sequence = sequence.then(() => engine.subtle.getSignatureParameters(privateKey, hashAlgorithm)); + sequence = sequence.then(result => { + parameters = result.parameters; + this.optionalSignature.signatureAlgorithm = result.signatureAlgorithm; + }); //endregion + //region Create TBS data for signing + + sequence = sequence.then(() => { + tbs = this.tbsRequest.toSchema(true).toBER(false); + }); //endregion + //region Signing TBS data on provided private key + + sequence = sequence.then(() => engine.subtle.signWithPrivateKey(tbs, privateKey, parameters)); + sequence = sequence.then(result => { + this.optionalSignature.signature = new asn1js.BitString({ + valueHex: result + }); + }); //endregion + + return sequence; + } //********************************************************************************** + + + verify() {} // TODO: Create the function + //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = OCSPRequest; + +},{"./CertID.js":18,"./Request.js":90,"./Signature.js":98,"./TBSRequest.js":105,"./common.js":110,"asn1js":112,"pvutils":113}],56:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _ResponseBytes = _interopRequireDefault(require("./ResponseBytes.js")); + +var _BasicOCSPResponse = _interopRequireDefault(require("./BasicOCSPResponse.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC6960 + */ +class OCSPResponse { + //********************************************************************************** + + /** + * Constructor for OCSPResponse class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {Enumerated} + * @desc responseStatus + */ + this.responseStatus = (0, _pvutils.getParametersValue)(parameters, "responseStatus", OCSPResponse.defaultValues("responseStatus")); + if ("responseBytes" in parameters) + /** + * @type {ResponseBytes} + * @desc responseBytes + */ + this.responseBytes = (0, _pvutils.getParametersValue)(parameters, "responseBytes", OCSPResponse.defaultValues("responseBytes")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "responseStatus": + return new asn1js.Enumerated(); + + case "responseBytes": + return new _ResponseBytes.default(); + + default: + throw new Error(`Invalid member name for OCSPResponse class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + + + static compareWithDefault(memberName, memberValue) { + switch (memberName) { + case "responseStatus": + return memberValue.isEqual(OCSPResponse.defaultValues(memberName)); + + case "responseBytes": + return _ResponseBytes.default.compareWithDefault("responseType", memberValue.responseType) && _ResponseBytes.default.compareWithDefault("response", memberValue.response); + + default: + throw new Error(`Invalid member name for OCSPResponse class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * OCSPResponse ::= SEQUENCE { + * responseStatus OCSPResponseStatus, + * responseBytes [0] EXPLICIT ResponseBytes OPTIONAL } + * + * OCSPResponseStatus ::= ENUMERATED { + * successful (0), -- Response has valid confirmations + * malformedRequest (1), -- Illegal confirmation request + * internalError (2), -- Internal error in issuer + * tryLater (3), -- Try again later + * -- (4) is not used + * sigRequired (5), -- Must sign the request + * unauthorized (6) -- Request unauthorized + * } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [responseStatus] + * @property {string} [responseBytes] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "OCSPResponse", + value: [new asn1js.Enumerated({ + name: names.responseStatus || "responseStatus" + }), new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: [_ResponseBytes.default.schema(names.responseBytes || { + names: { + blockName: "responseBytes" + } + })] + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["responseStatus", "responseBytes"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, OCSPResponse.schema()); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for OCSPResponse"); //endregion + //region Get internal properties from parsed schema + + this.responseStatus = asn1.result.responseStatus; + if ("responseBytes" in asn1.result) this.responseBytes = new _ResponseBytes.default({ + schema: asn1.result.responseBytes + }); //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Create array for output sequence + const outputArray = []; + outputArray.push(this.responseStatus); + + if ("responseBytes" in this) { + outputArray.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: [this.responseBytes.toSchema()] + })); + } //endregion + //region Construct and return new ASN.1 schema for this object + + + return new asn1js.Sequence({ + value: outputArray + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + const _object = { + responseStatus: this.responseStatus.toJSON() + }; + if ("responseBytes" in this) _object.responseBytes = this.responseBytes.toJSON(); + return _object; + } //********************************************************************************** + + /** + * Get OCSP response status for specific certificate + * @param {Certificate} certificate + * @param {Certificate} issuerCertificate + * @returns {*} + */ + + + getCertificateStatus(certificate, issuerCertificate) { + //region Initial variables + let basicResponse; + const result = { + isForCertificate: false, + status: 2 // 0 = good, 1 = revoked, 2 = unknown + + }; //endregion + //region Check that "ResponseBytes" contain "OCSP_BASIC_RESPONSE" + + if ("responseBytes" in this === false) return result; + if (this.responseBytes.responseType !== "1.3.6.1.5.5.7.48.1.1") // id-pkix-ocsp-basic + return result; + + try { + const asn1Basic = asn1js.fromBER(this.responseBytes.response.valueBlock.valueHex); + basicResponse = new _BasicOCSPResponse.default({ + schema: asn1Basic.result + }); + } catch (ex) { + return result; + } //endregion + + + return basicResponse.getCertificateStatus(certificate, issuerCertificate); + } //********************************************************************************** + + /** + * Make a signature for current OCSP Response + * @param {Object} privateKey Private key for "subjectPublicKeyInfo" structure + * @param {string} [hashAlgorithm] Hashing algorithm. Default SHA-1 + * @returns {Promise} + */ + + + sign(privateKey, hashAlgorithm) { + //region Check that ResponseData has type BasicOCSPResponse and sign it + if (this.responseBytes.responseType === "1.3.6.1.5.5.7.48.1.1") { + const asn1 = asn1js.fromBER(this.responseBytes.response.valueBlock.valueHex); + const basicResponse = new _BasicOCSPResponse.default({ + schema: asn1.result + }); + return basicResponse.sign(privateKey, hashAlgorithm); + } + + return Promise.reject(`Unknown ResponseBytes type: ${this.responseBytes.responseType}`); //endregion + } //********************************************************************************** + + /** + * Verify current OCSP Response + * @param {Certificate|null} issuerCertificate In order to decrease size of resp issuer cert could be ommited. In such case you need manually provide it. + * @returns {Promise} + */ + + + verify(issuerCertificate = null) { + //region Check that ResponseBytes exists in the object + if ("responseBytes" in this === false) return Promise.reject("Empty ResponseBytes field"); //endregion + //region Check that ResponceData has type BasicOCSPResponse and verify it + + if (this.responseBytes.responseType === "1.3.6.1.5.5.7.48.1.1") { + const asn1 = asn1js.fromBER(this.responseBytes.response.valueBlock.valueHex); + const basicResponse = new _BasicOCSPResponse.default({ + schema: asn1.result + }); + + if (issuerCertificate !== null) { + if ("certs" in basicResponse === false) basicResponse.certs = []; + basicResponse.certs.push(issuerCertificate); + } + + return basicResponse.verify(); + } + + return Promise.reject(`Unknown ResponseBytes type: ${this.responseBytes.responseType}`); //endregion + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = OCSPResponse; + +},{"./BasicOCSPResponse.js":13,"./ResponseBytes.js":91,"asn1js":112,"pvutils":113}],57:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _IssuerAndSerialNumber = _interopRequireDefault(require("./IssuerAndSerialNumber.js")); + +var _OriginatorPublicKey = _interopRequireDefault(require("./OriginatorPublicKey.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC5652 + */ +class OriginatorIdentifierOrKey { + //********************************************************************************** + + /** + * Constructor for OriginatorIdentifierOrKey class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {number} + * @desc variant + */ + this.variant = (0, _pvutils.getParametersValue)(parameters, "variant", OriginatorIdentifierOrKey.defaultValues("variant")); + if ("value" in parameters) + /** + * @type {IssuerAndSerialNumber|OctetString|OriginatorPublicKey} + * @desc value + */ + this.value = (0, _pvutils.getParametersValue)(parameters, "value", OriginatorIdentifierOrKey.defaultValues("value")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "variant": + return -1; + + case "value": + return {}; + + default: + throw new Error(`Invalid member name for OriginatorIdentifierOrKey class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + + + static compareWithDefault(memberName, memberValue) { + switch (memberName) { + case "variant": + return memberValue === -1; + + case "value": + return Object.keys(memberValue).length === 0; + + default: + throw new Error(`Invalid member name for OriginatorIdentifierOrKey class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * OriginatorIdentifierOrKey ::= CHOICE { + * issuerAndSerialNumber IssuerAndSerialNumber, + * subjectKeyIdentifier [0] SubjectKeyIdentifier, + * originatorKey [1] OriginatorPublicKey } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Choice({ + value: [_IssuerAndSerialNumber.default.schema({ + names: { + blockName: names.blockName || "" + } + }), new asn1js.Primitive({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + name: names.blockName || "" + }), new asn1js.Constructed({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + + }, + name: names.blockName || "", + value: _OriginatorPublicKey.default.schema().valueBlock.value + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["blockName"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, OriginatorIdentifierOrKey.schema({ + names: { + blockName: "blockName" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for OriginatorIdentifierOrKey"); //endregion + //region Get internal properties from parsed schema + + if (asn1.result.blockName.idBlock.tagClass === 1) { + this.variant = 1; + this.value = new _IssuerAndSerialNumber.default({ + schema: asn1.result.blockName + }); + } else { + if (asn1.result.blockName.idBlock.tagNumber === 0) { + //region Create "OCTETSTRING" from "ASN1_PRIMITIVE" + asn1.result.blockName.idBlock.tagClass = 1; // UNIVERSAL + + asn1.result.blockName.idBlock.tagNumber = 4; // OCTETSTRING + //endregion + + this.variant = 2; + this.value = asn1.result.blockName; + } else { + this.variant = 3; + this.value = new _OriginatorPublicKey.default({ + schema: new asn1js.Sequence({ + value: asn1.result.blockName.valueBlock.value + }) + }); + } + } //endregion + + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Construct and return new ASN.1 schema for this object + switch (this.variant) { + case 1: + return this.value.toSchema(); + + case 2: + this.value.idBlock.tagClass = 3; // CONTEXT-SPECIFIC + + this.value.idBlock.tagNumber = 0; // [0] + + return this.value; + + case 3: + { + const _schema = this.value.toSchema(); + + _schema.idBlock.tagClass = 3; // CONTEXT-SPECIFIC + + _schema.idBlock.tagNumber = 1; // [1] + + return _schema; + } + + default: + return new asn1js.Any(); + } //endregion + + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + const _object = { + variant: this.variant + }; + if (this.variant === 1 || this.variant === 2 || this.variant === 3) _object.value = this.value.toJSON(); + return _object; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = OriginatorIdentifierOrKey; + +},{"./IssuerAndSerialNumber.js":44,"./OriginatorPublicKey.js":59,"asn1js":112,"pvutils":113}],58:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _CertificateSet = _interopRequireDefault(require("./CertificateSet.js")); + +var _RevocationInfoChoices = _interopRequireDefault(require("./RevocationInfoChoices.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC5652 + */ +class OriginatorInfo { + //********************************************************************************** + + /** + * Constructor for OriginatorInfo class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + if ("certs" in parameters) + /** + * @type {CertificateSet} + * @desc certs + */ + this.certs = (0, _pvutils.getParametersValue)(parameters, "certs", OriginatorInfo.defaultValues("certs")); + if ("crls" in parameters) + /** + * @type {RevocationInfoChoices} + * @desc crls + */ + this.crls = (0, _pvutils.getParametersValue)(parameters, "crls", OriginatorInfo.defaultValues("crls")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "certs": + return new _CertificateSet.default(); + + case "crls": + return new _RevocationInfoChoices.default(); + + default: + throw new Error(`Invalid member name for OriginatorInfo class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + + + static compareWithDefault(memberName, memberValue) { + switch (memberName) { + case "certs": + return memberValue.certificates.length === 0; + + case "crls": + return memberValue.crls.length === 0 && memberValue.otherRevocationInfos.length === 0; + + default: + throw new Error(`Invalid member name for OriginatorInfo class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * OriginatorInfo ::= SEQUENCE { + * certs [0] IMPLICIT CertificateSet OPTIONAL, + * crls [1] IMPLICIT RevocationInfoChoices OPTIONAL } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [certs] + * @property {string} [crls] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [new asn1js.Constructed({ + name: names.certs || "", + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: _CertificateSet.default.schema().valueBlock.value + }), new asn1js.Constructed({ + name: names.crls || "", + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + + }, + value: _RevocationInfoChoices.default.schema().valueBlock.value + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["certs", "crls"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, OriginatorInfo.schema({ + names: { + certs: "certs", + crls: "crls" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for OriginatorInfo"); //endregion + //region Get internal properties from parsed schema + + if ("certs" in asn1.result) { + this.certs = new _CertificateSet.default({ + schema: new asn1js.Set({ + value: asn1.result.certs.valueBlock.value + }) + }); + } + + if ("crls" in asn1.result) { + this.crls = new _RevocationInfoChoices.default({ + schema: new asn1js.Set({ + value: asn1.result.crls.valueBlock.value + }) + }); + } //endregion + + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + const sequenceValue = []; + + if ("certs" in this) { + sequenceValue.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: this.certs.toSchema().valueBlock.value + })); + } + + if ("crls" in this) { + sequenceValue.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + + }, + value: this.crls.toSchema().valueBlock.value + })); + } //region Construct and return new ASN.1 schema for this object + + + return new asn1js.Sequence({ + value: sequenceValue + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + const object = {}; + if ("certs" in this) object.certs = this.certs.toJSON(); + if ("crls" in this) object.crls = this.crls.toJSON(); + return object; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = OriginatorInfo; + +},{"./CertificateSet.js":23,"./RevocationInfoChoices.js":93,"asn1js":112,"pvutils":113}],59:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _AlgorithmIdentifier = _interopRequireDefault(require("./AlgorithmIdentifier.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC5652 + */ +class OriginatorPublicKey { + //********************************************************************************** + + /** + * Constructor for OriginatorPublicKey class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {AlgorithmIdentifier} + * @desc algorithm + */ + this.algorithm = (0, _pvutils.getParametersValue)(parameters, "algorithm", OriginatorPublicKey.defaultValues("algorithm")); + /** + * @type {BitString} + * @desc publicKey + */ + + this.publicKey = (0, _pvutils.getParametersValue)(parameters, "publicKey", OriginatorPublicKey.defaultValues("publicKey")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "algorithm": + return new _AlgorithmIdentifier.default(); + + case "publicKey": + return new asn1js.BitString(); + + default: + throw new Error(`Invalid member name for OriginatorPublicKey class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + + + static compareWithDefault(memberName, memberValue) { + switch (memberName) { + case "algorithm": + case "publicKey": + return memberValue.isEqual(OriginatorPublicKey.defaultValues(memberName)); + + default: + throw new Error(`Invalid member name for OriginatorPublicKey class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * OriginatorPublicKey ::= SEQUENCE { + * algorithm AlgorithmIdentifier, + * publicKey BIT STRING } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [algorithm] + * @property {string} [publicKey] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [_AlgorithmIdentifier.default.schema(names.algorithm || {}), new asn1js.BitString({ + name: names.publicKey || "" + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["algorithm", "publicKey"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, OriginatorPublicKey.schema({ + names: { + algorithm: { + names: { + blockName: "algorithm" + } + }, + publicKey: "publicKey" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for OriginatorPublicKey"); //endregion + //region Get internal properties from parsed schema + + this.algorithm = new _AlgorithmIdentifier.default({ + schema: asn1.result.algorithm + }); + this.publicKey = asn1.result.publicKey; //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Construct and return new ASN.1 schema for this object + return new asn1js.Sequence({ + value: [this.algorithm.toSchema(), this.publicKey] + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + return { + algorithm: this.algorithm.toJSON(), + publicKey: this.publicKey.toJSON() + }; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = OriginatorPublicKey; + +},{"./AlgorithmIdentifier.js":4,"asn1js":112,"pvutils":113}],60:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC5652 + */ +class OtherCertificateFormat { + //********************************************************************************** + + /** + * Constructor for OtherCertificateFormat class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {string} + * @desc otherCertFormat + */ + this.otherCertFormat = (0, _pvutils.getParametersValue)(parameters, "otherCertFormat", OtherCertificateFormat.defaultValues("otherCertFormat")); + /** + * @type {Any} + * @desc otherCert + */ + + this.otherCert = (0, _pvutils.getParametersValue)(parameters, "otherCert", OtherCertificateFormat.defaultValues("otherCert")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "otherCertFormat": + return ""; + + case "otherCert": + return new asn1js.Any(); + + default: + throw new Error(`Invalid member name for OtherCertificateFormat class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * OtherCertificateFormat ::= SEQUENCE { + * otherCertFormat OBJECT IDENTIFIER, + * otherCert ANY DEFINED BY otherCertFormat } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [otherCertFormat] + * @property {string} [otherCert] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [new asn1js.ObjectIdentifier({ + name: names.otherCertFormat || "otherCertFormat" + }), new asn1js.Any({ + name: names.otherCert || "otherCert" + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["otherCertFormat", "otherCert"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, OtherCertificateFormat.schema()); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for OtherCertificateFormat"); //endregion + //region Get internal properties from parsed schema + + this.otherCertFormat = asn1.result.otherCertFormat.valueBlock.toString(); + this.otherCert = asn1.result.otherCert; //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Construct and return new ASN.1 schema for this object + return new asn1js.Sequence({ + value: [new asn1js.ObjectIdentifier({ + value: this.otherCertFormat + }), this.otherCert] + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + const object = { + otherCertFormat: this.otherCertFormat + }; + if (!(this.otherCert instanceof asn1js.Any)) object.otherCert = this.otherCert.toJSON(); + return object; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = OtherCertificateFormat; + +},{"asn1js":112,"pvutils":113}],61:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC5652 + */ +class OtherKeyAttribute { + //********************************************************************************** + + /** + * Constructor for OtherKeyAttribute class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {string} + * @desc keyAttrId + */ + this.keyAttrId = (0, _pvutils.getParametersValue)(parameters, "keyAttrId", OtherKeyAttribute.defaultValues("keyAttrId")); + if ("keyAttr" in parameters) + /** + * @type {*} + * @desc keyAttr + */ + this.keyAttr = (0, _pvutils.getParametersValue)(parameters, "keyAttr", OtherKeyAttribute.defaultValues("keyAttr")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "keyAttrId": + return ""; + + case "keyAttr": + return {}; + + default: + throw new Error(`Invalid member name for OtherKeyAttribute class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + + + static compareWithDefault(memberName, memberValue) { + switch (memberName) { + case "keyAttrId": + return memberValue === ""; + + case "keyAttr": + return Object.keys(memberValue).length === 0; + + default: + throw new Error(`Invalid member name for OtherKeyAttribute class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * OtherKeyAttribute ::= SEQUENCE { + * keyAttrId OBJECT IDENTIFIER, + * keyAttr ANY DEFINED BY keyAttrId OPTIONAL } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [optional] + * @property {string} [keyAttrId] + * @property {string} [keyAttr] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + optional: names.optional || true, + name: names.blockName || "", + value: [new asn1js.ObjectIdentifier({ + name: names.keyAttrId || "" + }), new asn1js.Any({ + optional: true, + name: names.keyAttr || "" + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["keyAttrId", "keyAttr"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, OtherKeyAttribute.schema({ + names: { + keyAttrId: "keyAttrId", + keyAttr: "keyAttr" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for OtherKeyAttribute"); //endregion + //region Get internal properties from parsed schema + + this.keyAttrId = asn1.result.keyAttrId.valueBlock.toString(); + if ("keyAttr" in asn1.result) this.keyAttr = asn1.result.keyAttr; //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Create array for output sequence + const outputArray = []; + outputArray.push(new asn1js.ObjectIdentifier({ + value: this.keyAttrId + })); + if ("keyAttr" in this) outputArray.push(this.keyAttr); //endregion + //region Construct and return new ASN.1 schema for this object + + return new asn1js.Sequence({ + value: outputArray + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + const _object = { + keyAttrId: this.keyAttrId + }; + if ("keyAttr" in this) _object.keyAttr = this.keyAttr.toJSON(); + return _object; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = OtherKeyAttribute; + +},{"asn1js":112,"pvutils":113}],62:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC3447 + */ +class OtherPrimeInfo { + //********************************************************************************** + + /** + * Constructor for OtherPrimeInfo class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {Integer} + * @desc prime + */ + this.prime = (0, _pvutils.getParametersValue)(parameters, "prime", OtherPrimeInfo.defaultValues("prime")); + /** + * @type {Integer} + * @desc exponent + */ + + this.exponent = (0, _pvutils.getParametersValue)(parameters, "exponent", OtherPrimeInfo.defaultValues("exponent")); + /** + * @type {Integer} + * @desc coefficient + */ + + this.coefficient = (0, _pvutils.getParametersValue)(parameters, "coefficient", OtherPrimeInfo.defaultValues("coefficient")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + //region If input argument array contains "json" for this object + + if ("json" in parameters) this.fromJSON(parameters.json); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "prime": + return new asn1js.Integer(); + + case "exponent": + return new asn1js.Integer(); + + case "coefficient": + return new asn1js.Integer(); + + default: + throw new Error(`Invalid member name for OtherPrimeInfo class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * OtherPrimeInfo ::= Sequence { + * prime Integer, -- ri + * exponent Integer, -- di + * coefficient Integer -- ti + * } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} prime + * @property {string} exponent + * @property {string} coefficient + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [new asn1js.Integer({ + name: names.prime || "" + }), new asn1js.Integer({ + name: names.exponent || "" + }), new asn1js.Integer({ + name: names.coefficient || "" + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["prime", "exponent", "coefficient"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, OtherPrimeInfo.schema({ + names: { + prime: "prime", + exponent: "exponent", + coefficient: "coefficient" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for OtherPrimeInfo"); //endregion + //region Get internal properties from parsed schema + + this.prime = asn1.result.prime.convertFromDER(); + this.exponent = asn1.result.exponent.convertFromDER(); + this.coefficient = asn1.result.coefficient.convertFromDER(); //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Construct and return new ASN.1 schema for this object + return new asn1js.Sequence({ + value: [this.prime.convertToDER(), this.exponent.convertToDER(), this.coefficient.convertToDER()] + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + return { + r: (0, _pvutils.toBase64)((0, _pvutils.arrayBufferToString)(this.prime.valueBlock.valueHex), true, true), + d: (0, _pvutils.toBase64)((0, _pvutils.arrayBufferToString)(this.exponent.valueBlock.valueHex), true, true), + t: (0, _pvutils.toBase64)((0, _pvutils.arrayBufferToString)(this.coefficient.valueBlock.valueHex), true, true) + }; + } //********************************************************************************** + + /** + * Convert JSON value into current object + * @param {Object} json + */ + + + fromJSON(json) { + if ("r" in json) this.prime = new asn1js.Integer({ + valueHex: (0, _pvutils.stringToArrayBuffer)((0, _pvutils.fromBase64)(json.r, true)) + });else throw new Error("Absent mandatory parameter \"r\""); + if ("d" in json) this.exponent = new asn1js.Integer({ + valueHex: (0, _pvutils.stringToArrayBuffer)((0, _pvutils.fromBase64)(json.d, true)) + });else throw new Error("Absent mandatory parameter \"d\""); + if ("t" in json) this.coefficient = new asn1js.Integer({ + valueHex: (0, _pvutils.stringToArrayBuffer)((0, _pvutils.fromBase64)(json.t, true)) + });else throw new Error("Absent mandatory parameter \"t\""); + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = OtherPrimeInfo; + +},{"asn1js":112,"pvutils":113}],63:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC5652 + */ +class OtherRecipientInfo { + //********************************************************************************** + + /** + * Constructor for OtherRecipientInfo class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {string} + * @desc oriType + */ + this.oriType = (0, _pvutils.getParametersValue)(parameters, "oriType", OtherRecipientInfo.defaultValues("oriType")); + /** + * @type {*} + * @desc oriValue + */ + + this.oriValue = (0, _pvutils.getParametersValue)(parameters, "oriValue", OtherRecipientInfo.defaultValues("oriValue")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "oriType": + return ""; + + case "oriValue": + return {}; + + default: + throw new Error(`Invalid member name for OtherRecipientInfo class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + + + static compareWithDefault(memberName, memberValue) { + switch (memberName) { + case "oriType": + return memberValue === ""; + + case "oriValue": + return Object.keys(memberValue).length === 0; + + default: + throw new Error(`Invalid member name for OtherRecipientInfo class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * OtherRecipientInfo ::= SEQUENCE { + * oriType OBJECT IDENTIFIER, + * oriValue ANY DEFINED BY oriType } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [oriType] + * @property {string} [oriValue] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [new asn1js.ObjectIdentifier({ + name: names.oriType || "" + }), new asn1js.Any({ + name: names.oriValue || "" + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["oriType", "oriValue"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, OtherRecipientInfo.schema({ + names: { + oriType: "oriType", + oriValue: "oriValue" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for OtherRecipientInfo"); //endregion + //region Get internal properties from parsed schema + + this.oriType = asn1.result.oriType.valueBlock.toString(); + this.oriValue = asn1.result.oriValue; //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Construct and return new ASN.1 schema for this object + return new asn1js.Sequence({ + value: [new asn1js.ObjectIdentifier({ + value: this.oriType + }), this.oriValue] + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + const _object = { + oriType: this.oriType + }; + if (OtherRecipientInfo.compareWithDefault("oriValue", this.oriValue) === false) _object.oriValue = this.oriValue.toJSON(); + return _object; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = OtherRecipientInfo; + +},{"asn1js":112,"pvutils":113}],64:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC5652 + */ +class OtherRevocationInfoFormat { + //********************************************************************************** + + /** + * Constructor for OtherRevocationInfoFormat class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {string} + * @desc otherRevInfoFormat + */ + this.otherRevInfoFormat = (0, _pvutils.getParametersValue)(parameters, "otherRevInfoFormat", OtherRevocationInfoFormat.defaultValues("otherRevInfoFormat")); + /** + * @type {Any} + * @desc otherRevInfo + */ + + this.otherRevInfo = (0, _pvutils.getParametersValue)(parameters, "otherRevInfo", OtherRevocationInfoFormat.defaultValues("otherRevInfo")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "otherRevInfoFormat": + return ""; + + case "otherRevInfo": + return new asn1js.Any(); + + default: + throw new Error(`Invalid member name for OtherRevocationInfoFormat class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * OtherCertificateFormat ::= SEQUENCE { + * otherRevInfoFormat OBJECT IDENTIFIER, + * otherRevInfo ANY DEFINED BY otherCertFormat } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [otherRevInfoFormat] + * @property {string} [otherRevInfo] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [new asn1js.ObjectIdentifier({ + name: names.otherRevInfoFormat || "otherRevInfoFormat" + }), new asn1js.Any({ + name: names.otherRevInfo || "otherRevInfo" + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["otherRevInfoFormat", "otherRevInfo"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, OtherRevocationInfoFormat.schema()); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for OtherRevocationInfoFormat"); //endregion + //region Get internal properties from parsed schema + + this.otherRevInfoFormat = asn1.result.otherRevInfoFormat.valueBlock.toString(); + this.otherRevInfo = asn1.result.otherRevInfo; //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Construct and return new ASN.1 schema for this object + return new asn1js.Sequence({ + value: [new asn1js.ObjectIdentifier({ + value: this.otherRevInfoFormat + }), this.otherRevInfo] + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + const object = { + otherRevInfoFormat: this.otherRevInfoFormat + }; + if (!(this.otherRevInfo instanceof asn1js.Any)) object.otherRevInfo = this.otherRevInfo.toJSON(); + return object; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = OtherRevocationInfoFormat; + +},{"asn1js":112,"pvutils":113}],65:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _AlgorithmIdentifier = _interopRequireDefault(require("./AlgorithmIdentifier.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC2898 + */ +class PBES2Params { + //********************************************************************************** + + /** + * Constructor for PBES2Params class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {AlgorithmIdentifier} + * @desc keyDerivationFunc + */ + this.keyDerivationFunc = (0, _pvutils.getParametersValue)(parameters, "keyDerivationFunc", PBES2Params.defaultValues("keyDerivationFunc")); + /** + * @type {AlgorithmIdentifier} + * @desc encryptionScheme + */ + + this.encryptionScheme = (0, _pvutils.getParametersValue)(parameters, "encryptionScheme", PBES2Params.defaultValues("encryptionScheme")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "keyDerivationFunc": + return new _AlgorithmIdentifier.default(); + + case "encryptionScheme": + return new _AlgorithmIdentifier.default(); + + default: + throw new Error(`Invalid member name for PBES2Params class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * PBES2-params ::= SEQUENCE { + * keyDerivationFunc AlgorithmIdentifier {{PBES2-KDFs}}, + * encryptionScheme AlgorithmIdentifier {{PBES2-Encs}} } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [keyDerivationFunc] + * @property {string} [encryptionScheme] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [_AlgorithmIdentifier.default.schema(names.keyDerivationFunc || {}), _AlgorithmIdentifier.default.schema(names.encryptionScheme || {})] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["keyDerivationFunc", "encryptionScheme"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, PBES2Params.schema({ + names: { + keyDerivationFunc: { + names: { + blockName: "keyDerivationFunc" + } + }, + encryptionScheme: { + names: { + blockName: "encryptionScheme" + } + } + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for PBES2Params"); //endregion + //region Get internal properties from parsed schema + + this.keyDerivationFunc = new _AlgorithmIdentifier.default({ + schema: asn1.result.keyDerivationFunc + }); + this.encryptionScheme = new _AlgorithmIdentifier.default({ + schema: asn1.result.encryptionScheme + }); //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Construct and return new ASN.1 schema for this object + return new asn1js.Sequence({ + value: [this.keyDerivationFunc.toSchema(), this.encryptionScheme.toSchema()] + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + return { + keyDerivationFunc: this.keyDerivationFunc.toJSON(), + encryptionScheme: this.encryptionScheme.toJSON() + }; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = PBES2Params; + +},{"./AlgorithmIdentifier.js":4,"asn1js":112,"pvutils":113}],66:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _AlgorithmIdentifier = _interopRequireDefault(require("./AlgorithmIdentifier.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC2898 + */ +class PBKDF2Params { + //********************************************************************************** + + /** + * Constructor for PBKDF2Params class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {Object} + * @desc salt + */ + this.salt = (0, _pvutils.getParametersValue)(parameters, "salt", PBKDF2Params.defaultValues("salt")); + /** + * @type {number} + * @desc iterationCount + */ + + this.iterationCount = (0, _pvutils.getParametersValue)(parameters, "iterationCount", PBKDF2Params.defaultValues("iterationCount")); + if ("keyLength" in parameters) + /** + * @type {number} + * @desc keyLength + */ + this.keyLength = (0, _pvutils.getParametersValue)(parameters, "keyLength", PBKDF2Params.defaultValues("keyLength")); + if ("prf" in parameters) + /** + * @type {AlgorithmIdentifier} + * @desc prf + */ + this.prf = (0, _pvutils.getParametersValue)(parameters, "prf", PBKDF2Params.defaultValues("prf")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "salt": + return {}; + + case "iterationCount": + return -1; + + case "keyLength": + return 0; + + case "prf": + return new _AlgorithmIdentifier.default({ + algorithmId: "1.3.14.3.2.26", + // SHA-1 + algorithmParams: new asn1js.Null() + }); + + default: + throw new Error(`Invalid member name for PBKDF2Params class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * PBKDF2-params ::= SEQUENCE { + * salt CHOICE { + * specified OCTET STRING, + * otherSource AlgorithmIdentifier }, + * iterationCount INTEGER (1..MAX), + * keyLength INTEGER (1..MAX) OPTIONAL, + * prf AlgorithmIdentifier + * DEFAULT { algorithm hMAC-SHA1, parameters NULL } } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [saltPrimitive] + * @property {string} [saltConstructed] + * @property {string} [iterationCount] + * @property {string} [keyLength] + * @property {string} [prf] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [new asn1js.Choice({ + value: [new asn1js.OctetString({ + name: names.saltPrimitive || "" + }), _AlgorithmIdentifier.default.schema(names.saltConstructed || {})] + }), new asn1js.Integer({ + name: names.iterationCount || "" + }), new asn1js.Integer({ + name: names.keyLength || "", + optional: true + }), _AlgorithmIdentifier.default.schema(names.prf || { + names: { + optional: true + } + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["salt", "iterationCount", "keyLength", "prf"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, PBKDF2Params.schema({ + names: { + saltPrimitive: "salt", + saltConstructed: { + names: { + blockName: "salt" + } + }, + iterationCount: "iterationCount", + keyLength: "keyLength", + prf: { + names: { + blockName: "prf", + optional: true + } + } + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for PBKDF2Params"); //endregion + //region Get internal properties from parsed schema + + this.salt = asn1.result.salt; + this.iterationCount = asn1.result.iterationCount.valueBlock.valueDec; + if ("keyLength" in asn1.result) this.keyLength = asn1.result.keyLength.valueBlock.valueDec; + if ("prf" in asn1.result) this.prf = new _AlgorithmIdentifier.default({ + schema: asn1.result.prf + }); //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Create array for output sequence + const outputArray = []; + outputArray.push(this.salt); + outputArray.push(new asn1js.Integer({ + value: this.iterationCount + })); + + if ("keyLength" in this) { + if (PBKDF2Params.defaultValues("keyLength") !== this.keyLength) outputArray.push(new asn1js.Integer({ + value: this.keyLength + })); + } + + if ("prf" in this) { + if (PBKDF2Params.defaultValues("prf").isEqual(this.prf) === false) outputArray.push(this.prf.toSchema()); + } //endregion + //region Construct and return new ASN.1 schema for this object + + + return new asn1js.Sequence({ + value: outputArray + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + const _object = { + salt: this.salt.toJSON(), + iterationCount: this.iterationCount + }; + + if ("keyLength" in this) { + if (PBKDF2Params.defaultValues("keyLength") !== this.keyLength) _object.keyLength = this.keyLength; + } + + if ("prf" in this) { + if (PBKDF2Params.defaultValues("prf").isEqual(this.prf) === false) _object.prf = this.prf.toJSON(); + } + + return _object; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = PBKDF2Params; + +},{"./AlgorithmIdentifier.js":4,"asn1js":112,"pvutils":113}],67:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _common = require("./common.js"); + +var _ContentInfo = _interopRequireDefault(require("./ContentInfo.js")); + +var _MacData = _interopRequireDefault(require("./MacData.js")); + +var _DigestInfo = _interopRequireDefault(require("./DigestInfo.js")); + +var _AlgorithmIdentifier = _interopRequireDefault(require("./AlgorithmIdentifier.js")); + +var _SignedData = _interopRequireDefault(require("./SignedData.js")); + +var _EncapsulatedContentInfo = _interopRequireDefault(require("./EncapsulatedContentInfo.js")); + +var _Attribute = _interopRequireDefault(require("./Attribute.js")); + +var _SignerInfo = _interopRequireDefault(require("./SignerInfo.js")); + +var _IssuerAndSerialNumber = _interopRequireDefault(require("./IssuerAndSerialNumber.js")); + +var _SignedAndUnsignedAttributes = _interopRequireDefault(require("./SignedAndUnsignedAttributes.js")); + +var _AuthenticatedSafe = _interopRequireDefault(require("./AuthenticatedSafe.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC7292 + */ +class PFX { + //********************************************************************************** + + /** + * Constructor for PFX class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {number} + * @desc version + */ + this.version = (0, _pvutils.getParametersValue)(parameters, "version", PFX.defaultValues("version")); + /** + * @type {ContentInfo} + * @desc authSafe + */ + + this.authSafe = (0, _pvutils.getParametersValue)(parameters, "authSafe", PFX.defaultValues("authSafe")); + if ("macData" in parameters) + /** + * @type {MacData} + * @desc macData + */ + this.macData = (0, _pvutils.getParametersValue)(parameters, "macData", PFX.defaultValues("macData")); + if ("parsedValue" in parameters) + /** + * @type {*} + * @desc parsedValue + */ + this.parsedValue = (0, _pvutils.getParametersValue)(parameters, "parsedValue", PFX.defaultValues("parsedValue")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "version": + return 3; + + case "authSafe": + return new _ContentInfo.default(); + + case "macData": + return new _MacData.default(); + + case "parsedValue": + return {}; + + default: + throw new Error(`Invalid member name for PFX class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + + + static compareWithDefault(memberName, memberValue) { + switch (memberName) { + case "version": + return memberValue === PFX.defaultValues(memberName); + + case "authSafe": + return _ContentInfo.default.compareWithDefault("contentType", memberValue.contentType) && _ContentInfo.default.compareWithDefault("content", memberValue.content); + + case "macData": + return _MacData.default.compareWithDefault("mac", memberValue.mac) && _MacData.default.compareWithDefault("macSalt", memberValue.macSalt) && _MacData.default.compareWithDefault("iterations", memberValue.iterations); + + case "parsedValue": + return memberValue instanceof Object && Object.keys(memberValue).length === 0; + + default: + throw new Error(`Invalid member name for PFX class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * PFX ::= SEQUENCE { + * version INTEGER {v3(3)}(v3,...), + * authSafe ContentInfo, + * macData MacData OPTIONAL + * } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [version] + * @property {string} [authSafe] + * @property {string} [macData] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [new asn1js.Integer({ + name: names.version || "version" + }), _ContentInfo.default.schema(names.authSafe || { + names: { + blockName: "authSafe" + } + }), _MacData.default.schema(names.macData || { + names: { + blockName: "macData", + optional: true + } + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["version", "authSafe", "macData"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, PFX.schema({ + names: { + version: "version", + authSafe: { + names: { + blockName: "authSafe" + } + }, + macData: { + names: { + blockName: "macData" + } + } + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for PFX"); //endregion + //region Get internal properties from parsed schema + + this.version = asn1.result.version.valueBlock.valueDec; + this.authSafe = new _ContentInfo.default({ + schema: asn1.result.authSafe + }); + if ("macData" in asn1.result) this.macData = new _MacData.default({ + schema: asn1.result.macData + }); //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Construct and return new ASN.1 schema for this object + const outputArray = [new asn1js.Integer({ + value: this.version + }), this.authSafe.toSchema()]; + if ("macData" in this) outputArray.push(this.macData.toSchema()); + return new asn1js.Sequence({ + value: outputArray + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + const output = { + version: this.version, + authSafe: this.authSafe.toJSON() + }; + if ("macData" in this) output.macData = this.macData.toJSON(); + return output; + } //********************************************************************************** + + /** + * Making ContentInfo from "parsedValue" object + * @param {Object} parameters Parameters, specific to each "integrity mode" + */ + + + makeInternalValues(parameters = {}) { + //region Check mandatory parameter + if (parameters instanceof Object === false) return Promise.reject("The \"parameters\" must has \"Object\" type"); + if ("parsedValue" in this === false) return Promise.reject("Please call \"parseValues\" function first in order to make \"parsedValue\" data"); + if ("integrityMode" in this.parsedValue === false) return Promise.reject("Absent mandatory parameter \"integrityMode\" inside \"parsedValue\""); //endregion + //region Initial variables + + let sequence = Promise.resolve(); //endregion + //region Get a "crypto" extension + + const crypto = (0, _common.getCrypto)(); + if (typeof crypto === "undefined") return Promise.reject("Unable to create WebCrypto object"); //endregion + //region Makes values for each particular integrity mode + //region Check that we do have neccessary fields in "parsedValue" object + + if ("authenticatedSafe" in this.parsedValue === false) return Promise.reject("Absent mandatory parameter \"authenticatedSafe\" in \"parsedValue\""); //endregion + + switch (this.parsedValue.integrityMode) { + //region HMAC-based integrity + case 0: + { + //region Check additional mandatory parameters + if ("iterations" in parameters === false) return Promise.reject("Absent mandatory parameter \"iterations\""); + if ("pbkdf2HashAlgorithm" in parameters === false) return Promise.reject("Absent mandatory parameter \"pbkdf2HashAlgorithm\""); + if ("hmacHashAlgorithm" in parameters === false) return Promise.reject("Absent mandatory parameter \"hmacHashAlgorithm\""); + if ("password" in parameters === false) return Promise.reject("Absent mandatory parameter \"password\""); //endregion + //region Initial variables + + const saltBuffer = new ArrayBuffer(64); + const saltView = new Uint8Array(saltBuffer); + (0, _common.getRandomValues)(saltView); + const data = this.parsedValue.authenticatedSafe.toSchema().toBER(false); + this.authSafe = new _ContentInfo.default({ + contentType: "1.2.840.113549.1.7.1", + content: new asn1js.OctetString({ + valueHex: data + }) + }); //endregion + //region Call current crypto engine for making HMAC-based data stamp + + const engine = (0, _common.getEngine)(); + if ("stampDataWithPassword" in engine.subtle === false) return Promise.reject(`No support for "stampDataWithPassword" in current engine "${engine.name}"`); + sequence = sequence.then(() => engine.subtle.stampDataWithPassword({ + password: parameters.password, + hashAlgorithm: parameters.hmacHashAlgorithm, + salt: saltBuffer, + iterationCount: parameters.iterations, + contentToStamp: data + })); //endregion + //region Make "MacData" values + + sequence = sequence.then(result => { + this.macData = new _MacData.default({ + mac: new _DigestInfo.default({ + digestAlgorithm: new _AlgorithmIdentifier.default({ + algorithmId: (0, _common.getOIDByAlgorithm)({ + name: parameters.hmacHashAlgorithm + }) + }), + digest: new asn1js.OctetString({ + valueHex: result + }) + }), + macSalt: new asn1js.OctetString({ + valueHex: saltBuffer + }), + iterations: parameters.iterations + }); + }, error => Promise.reject(error)); //endregion + //endregion + } + break; + //endregion + //region publicKey-based integrity + + case 1: + { + //region Check additional mandatory parameters + if ("signingCertificate" in parameters === false) return Promise.reject("Absent mandatory parameter \"signingCertificate\""); + if ("privateKey" in parameters === false) return Promise.reject("Absent mandatory parameter \"privateKey\""); + if ("hashAlgorithm" in parameters === false) return Promise.reject("Absent mandatory parameter \"hashAlgorithm\""); //endregion + //region Making data to be signed + // NOTE: all internal data for "authenticatedSafe" must be already prepared. + // Thus user must call "makeValues" for all internal "SafeContent" value with appropriate parameters. + // Or user can choose to use values from initial parsing of existing PKCS#12 data. + + const toBeSigned = this.parsedValue.authenticatedSafe.toSchema().toBER(false); //endregion + //region Initial variables + + const cmsSigned = new _SignedData.default({ + version: 1, + encapContentInfo: new _EncapsulatedContentInfo.default({ + eContentType: "1.2.840.113549.1.7.1", + // "data" content type + eContent: new asn1js.OctetString({ + valueHex: toBeSigned + }) + }), + certificates: [parameters.signingCertificate] + }); //endregion + //region Making additional attributes for CMS Signed Data + //region Create a message digest + + sequence = sequence.then(() => crypto.digest({ + name: parameters.hashAlgorithm + }, new Uint8Array(toBeSigned))); //endregion + //region Combine all signed extensions + + sequence = sequence.then(result => { + //region Initial variables + const signedAttr = []; //endregion + //region contentType + + signedAttr.push(new _Attribute.default({ + type: "1.2.840.113549.1.9.3", + values: [new asn1js.ObjectIdentifier({ + value: "1.2.840.113549.1.7.1" + })] + })); //endregion + //region signingTime + + signedAttr.push(new _Attribute.default({ + type: "1.2.840.113549.1.9.5", + values: [new asn1js.UTCTime({ + valueDate: new Date() + })] + })); //endregion + //region messageDigest + + signedAttr.push(new _Attribute.default({ + type: "1.2.840.113549.1.9.4", + values: [new asn1js.OctetString({ + valueHex: result + })] + })); //endregion + //region Making final value for "SignerInfo" type + + cmsSigned.signerInfos.push(new _SignerInfo.default({ + version: 1, + sid: new _IssuerAndSerialNumber.default({ + issuer: parameters.signingCertificate.issuer, + serialNumber: parameters.signingCertificate.serialNumber + }), + signedAttrs: new _SignedAndUnsignedAttributes.default({ + type: 0, + attributes: signedAttr + }) + })); //endregion + }, error => Promise.reject(`Error during making digest for message: ${error}`)); //endregion + //endregion + //region Signing CMS Signed Data + + sequence = sequence.then(() => cmsSigned.sign(parameters.privateKey, 0, parameters.hashAlgorithm)); //endregion + //region Making final CMS_CONTENT_INFO type + + sequence = sequence.then(() => { + this.authSafe = new _ContentInfo.default({ + contentType: "1.2.840.113549.1.7.2", + content: cmsSigned.toSchema(true) + }); + }, error => Promise.reject(`Error during making signature: ${error}`)); //endregion + } + break; + //endregion + //region default + + default: + return Promise.reject(`Parameter "integrityMode" has unknown value: ${parameters.integrityMode}`); + //endregion + } //endregion + + + return sequence; + } //********************************************************************************** + + + parseInternalValues(parameters) { + //region Check input data from "parameters" + if (parameters instanceof Object === false) return Promise.reject("The \"parameters\" must has \"Object\" type"); + if ("checkIntegrity" in parameters === false) parameters.checkIntegrity = true; //endregion + //region Initial variables + + let sequence = Promise.resolve(); //endregion + //region Get a "crypto" extension + + const crypto = (0, _common.getCrypto)(); + if (typeof crypto === "undefined") return Promise.reject("Unable to create WebCrypto object"); //endregion + //region Create value for "this.parsedValue.authenticatedSafe" and check integrity + + this.parsedValue = {}; + + switch (this.authSafe.contentType) { + //region data + case "1.2.840.113549.1.7.1": + { + //region Check additional mandatory parameters + if ("password" in parameters === false) return Promise.reject("Absent mandatory parameter \"password\""); //endregion + //region Integrity based on HMAC + + this.parsedValue.integrityMode = 0; //endregion + //region Check that we do have OCTETSTRING as "content" + + if (this.authSafe.content instanceof asn1js.OctetString === false) return Promise.reject("Wrong type of \"this.authSafe.content\""); //endregion + //region Check we have "constructive encoding" for AuthSafe content + + let authSafeContent = new ArrayBuffer(0); + + if (this.authSafe.content.valueBlock.isConstructed) { + var _iteratorNormalCompletion = true; + var _didIteratorError = false; + var _iteratorError = undefined; + + try { + for (var _iterator = this.authSafe.content.valueBlock.value[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { + const contentValue = _step.value; + authSafeContent = (0, _pvutils.utilConcatBuf)(authSafeContent, contentValue.valueBlock.valueHex); + } + } catch (err) { + _didIteratorError = true; + _iteratorError = err; + } finally { + try { + if (!_iteratorNormalCompletion && _iterator.return != null) { + _iterator.return(); + } + } finally { + if (_didIteratorError) { + throw _iteratorError; + } + } + } + } else authSafeContent = this.authSafe.content.valueBlock.valueHex; //endregion + //region Parse internal ASN.1 data + + + const asn1 = asn1js.fromBER(authSafeContent); + if (asn1.offset === -1) return Promise.reject("Error during parsing of ASN.1 data inside \"this.authSafe.content\""); //endregion + //region Set "authenticatedSafe" value + + this.parsedValue.authenticatedSafe = new _AuthenticatedSafe.default({ + schema: asn1.result + }); //endregion + //region Check integrity + + if (parameters.checkIntegrity) { + //region Check that "MacData" exists + if ("macData" in this === false) return Promise.reject("Absent \"macData\" value, can not check PKCS#12 data integrity"); //endregion + //region Initial variables + + const hashAlgorithm = (0, _common.getAlgorithmByOID)(this.macData.mac.digestAlgorithm.algorithmId); + if ("name" in hashAlgorithm === false) return Promise.reject(`Unsupported digest algorithm: ${this.macData.mac.digestAlgorithm.algorithmId}`); //endregion + //region Call current crypto engine for verifying HMAC-based data stamp + + const engine = (0, _common.getEngine)(); + sequence = sequence.then(() => engine.subtle.verifyDataStampedWithPassword({ + password: parameters.password, + hashAlgorithm: hashAlgorithm.name, + salt: this.macData.macSalt.valueBlock.valueHex, + iterationCount: this.macData.iterations, + contentToVerify: authSafeContent, + signatureToVerify: this.macData.mac.digest.valueBlock.valueHex + })); //endregion + //region Verify HMAC signature + + sequence = sequence.then(result => { + if (result === false) return Promise.reject("Integrity for the PKCS#12 data is broken!"); + return Promise.resolve(); + }, error => Promise.reject(error)); //endregion + } //endregion + + } + break; + //endregion + //region signedData + + case "1.2.840.113549.1.7.2": + { + //region Integrity based on signature using public key + this.parsedValue.integrityMode = 1; //endregion + //region Parse CMS Signed Data + + const cmsSigned = new _SignedData.default({ + schema: this.authSafe.content + }); //endregion + //region Check that we do have OCTETSTRING as "content" + + if ("eContent" in cmsSigned.encapContentInfo === false) return Promise.reject("Absent of attached data in \"cmsSigned.encapContentInfo\""); + if (cmsSigned.encapContentInfo.eContent instanceof asn1js.OctetString === false) return Promise.reject("Wrong type of \"cmsSigned.encapContentInfo.eContent\""); //endregion + //region Create correct data block for verification + + let data = new ArrayBuffer(0); + if (cmsSigned.encapContentInfo.eContent.idBlock.isConstructed === false) data = cmsSigned.encapContentInfo.eContent.valueBlock.valueHex;else { + for (let i = 0; i < cmsSigned.encapContentInfo.eContent.valueBlock.value.length; i++) data = (0, _pvutils.utilConcatBuf)(data, cmsSigned.encapContentInfo.eContent.valueBlock.value[i].valueBlock.valueHex); + } //endregion + //region Parse internal ASN.1 data + + const asn1 = asn1js.fromBER(data); + if (asn1.offset === -1) return Promise.reject("Error during parsing of ASN.1 data inside \"this.authSafe.content\""); //endregion + //region Set "authenticatedSafe" value + + this.parsedValue.authenticatedSafe = new _AuthenticatedSafe.default({ + schema: asn1.result + }); //endregion + //region Check integrity + + sequence = sequence.then(() => cmsSigned.verify({ + signer: 0, + checkChain: false + })).then(result => { + if (result === false) return Promise.reject("Integrity for the PKCS#12 data is broken!"); + return Promise.resolve(); + }, error => Promise.reject(`Error during integrity verification: ${error}`)); //endregion + } + break; + //endregion + //region default + + default: + return Promise.reject(`Incorrect value for "this.authSafe.contentType": ${this.authSafe.contentType}`); + //endregion + } //endregion + //region Return result of the function + + + return sequence.then(() => this, error => Promise.reject(`Error during parsing: ${error}`)); //endregion + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = PFX; + +},{"./AlgorithmIdentifier.js":4,"./Attribute.js":6,"./AuthenticatedSafe.js":10,"./ContentInfo.js":26,"./DigestInfo.js":28,"./EncapsulatedContentInfo.js":33,"./IssuerAndSerialNumber.js":44,"./MacData.js":52,"./SignedAndUnsignedAttributes.js":99,"./SignedData.js":101,"./SignerInfo.js":102,"./common.js":110,"asn1js":112,"pvutils":113}],68:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _AlgorithmIdentifier = _interopRequireDefault(require("./AlgorithmIdentifier.js")); + +var _EncryptedData = _interopRequireDefault(require("./EncryptedData.js")); + +var _EncryptedContentInfo = _interopRequireDefault(require("./EncryptedContentInfo.js")); + +var _PrivateKeyInfo = _interopRequireDefault(require("./PrivateKeyInfo.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC7292 + */ +class PKCS8ShroudedKeyBag { + //********************************************************************************** + + /** + * Constructor for PKCS8ShroudedKeyBag class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {AlgorithmIdentifier} + * @desc encryptionAlgorithm + */ + this.encryptionAlgorithm = (0, _pvutils.getParametersValue)(parameters, "encryptionAlgorithm", PKCS8ShroudedKeyBag.defaultValues("encryptionAlgorithm")); + /** + * @type {OctetString} + * @desc encryptedData + */ + + this.encryptedData = (0, _pvutils.getParametersValue)(parameters, "encryptedData", PKCS8ShroudedKeyBag.defaultValues("encryptedData")); + if ("parsedValue" in parameters) + /** + * @type {*} + * @desc parsedValue + */ + this.parsedValue = (0, _pvutils.getParametersValue)(parameters, "parsedValue", PKCS8ShroudedKeyBag.defaultValues("parsedValue")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "encryptionAlgorithm": + return new _AlgorithmIdentifier.default(); + + case "encryptedData": + return new asn1js.OctetString(); + + case "parsedValue": + return {}; + + default: + throw new Error(`Invalid member name for PKCS8ShroudedKeyBag class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + + + static compareWithDefault(memberName, memberValue) { + switch (memberName) { + case "encryptionAlgorithm": + return _AlgorithmIdentifier.default.compareWithDefault("algorithmId", memberValue.algorithmId) && "algorithmParams" in memberValue === false; + + case "encryptedData": + return memberValue.isEqual(PKCS8ShroudedKeyBag.defaultValues(memberName)); + + case "parsedValue": + return memberValue instanceof Object && Object.keys(memberValue).length === 0; + + default: + throw new Error(`Invalid member name for PKCS8ShroudedKeyBag class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * PKCS8ShroudedKeyBag ::= EncryptedPrivateKeyInfo + * + * EncryptedPrivateKeyInfo ::= SEQUENCE { + * encryptionAlgorithm AlgorithmIdentifier {{KeyEncryptionAlgorithms}}, + * encryptedData EncryptedData + * } + * + * EncryptedData ::= OCTET STRING + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [encryptionAlgorithm] + * @property {string} [encryptedData] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [_AlgorithmIdentifier.default.schema(names.encryptionAlgorithm || { + names: { + blockName: "encryptionAlgorithm" + } + }), new asn1js.Choice({ + value: [new asn1js.OctetString({ + name: names.encryptedData || "encryptedData" + }), new asn1js.OctetString({ + idBlock: { + isConstructed: true + }, + name: names.encryptedData || "encryptedData" + })] + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["encryptionAlgorithm", "encryptedData"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, PKCS8ShroudedKeyBag.schema({ + names: { + encryptionAlgorithm: { + names: { + blockName: "encryptionAlgorithm" + } + }, + encryptedData: "encryptedData" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for PKCS8ShroudedKeyBag"); //endregion + //region Get internal properties from parsed schema + + this.encryptionAlgorithm = new _AlgorithmIdentifier.default({ + schema: asn1.result.encryptionAlgorithm + }); + this.encryptedData = asn1.result.encryptedData; //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Construct and return new ASN.1 schema for this object + return new asn1js.Sequence({ + value: [this.encryptionAlgorithm.toSchema(), this.encryptedData] + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + return { + encryptionAlgorithm: this.encryptionAlgorithm.toJSON(), + encryptedData: this.encryptedData.toJSON() + }; + } //********************************************************************************** + + + parseInternalValues(parameters) { + //region Initial variables + let sequence = Promise.resolve(); + const cmsEncrypted = new _EncryptedData.default({ + encryptedContentInfo: new _EncryptedContentInfo.default({ + contentEncryptionAlgorithm: this.encryptionAlgorithm, + encryptedContent: this.encryptedData + }) + }); //endregion + //region Decrypt internal data + + sequence = sequence.then(() => cmsEncrypted.decrypt(parameters), error => Promise.reject(error)); //endregion + //region Initialize "parsedValue" with decrypted PKCS#8 private key + + sequence = sequence.then( + /** + * @param {ArrayBuffer} result + */ + result => { + const asn1 = asn1js.fromBER(result); + if (asn1.offset === -1) return Promise.reject("Error during parsing ASN.1 data"); + this.parsedValue = new _PrivateKeyInfo.default({ + schema: asn1.result + }); + return Promise.resolve(); + }, error => Promise.reject(error)); //endregion + + return sequence; + } //********************************************************************************** + + + makeInternalValues(parameters) { + //region Check that we do have "parsedValue" + if ("parsedValue" in this === false) return Promise.reject("Please initialize \"parsedValue\" first"); //endregion + //region Initial variables + + let sequence = Promise.resolve(); + const cmsEncrypted = new _EncryptedData.default(); //endregion + //region Encrypt internal data + + sequence = sequence.then(() => { + parameters.contentToEncrypt = this.parsedValue.toSchema().toBER(false); + return cmsEncrypted.encrypt(parameters); + }, error => Promise.reject(error)); //endregion + //region Initialize internal values + + sequence = sequence.then(() => { + this.encryptionAlgorithm = cmsEncrypted.encryptedContentInfo.contentEncryptionAlgorithm; + this.encryptedData = cmsEncrypted.encryptedContentInfo.encryptedContent; + }); //endregion + + return sequence; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = PKCS8ShroudedKeyBag; + +},{"./AlgorithmIdentifier.js":4,"./EncryptedContentInfo.js":34,"./EncryptedData.js":35,"./PrivateKeyInfo.js":76,"asn1js":112,"pvutils":113}],69:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC3161 + */ +class PKIStatusInfo { + //********************************************************************************** + + /** + * Constructor for PKIStatusInfo class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {number} + * @desc status + */ + this.status = (0, _pvutils.getParametersValue)(parameters, "status", PKIStatusInfo.defaultValues("status")); + if ("statusStrings" in parameters) + /** + * @type {Array.} + * @desc statusStrings + */ + this.statusStrings = (0, _pvutils.getParametersValue)(parameters, "statusStrings", PKIStatusInfo.defaultValues("statusStrings")); + if ("failInfo" in parameters) + /** + * @type {BitString} + * @desc failInfo + */ + this.failInfo = (0, _pvutils.getParametersValue)(parameters, "failInfo", PKIStatusInfo.defaultValues("failInfo")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "status": + return 2; + + case "statusStrings": + return []; + + case "failInfo": + return new asn1js.BitString(); + + default: + throw new Error(`Invalid member name for PKIStatusInfo class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + + + static compareWithDefault(memberName, memberValue) { + switch (memberName) { + case "status": + return memberValue === PKIStatusInfo.defaultValues(memberName); + + case "statusStrings": + return memberValue.length === 0; + + case "failInfo": + return memberValue.isEqual(PKIStatusInfo.defaultValues(memberName)); + + default: + throw new Error(`Invalid member name for PKIStatusInfo class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * PKIStatusInfo ::= SEQUENCE { + * status PKIStatus, + * statusString PKIFreeText OPTIONAL, + * failInfo PKIFailureInfo OPTIONAL } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [status] + * @property {string} [statusStrings] + * @property {string} [failInfo] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [new asn1js.Integer({ + name: names.status || "" + }), new asn1js.Sequence({ + optional: true, + value: [new asn1js.Repeated({ + name: names.statusStrings || "", + value: new asn1js.Utf8String() + })] + }), new asn1js.BitString({ + name: names.failInfo || "", + optional: true + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["status", "statusStrings", "failInfo"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, PKIStatusInfo.schema({ + names: { + status: "status", + statusStrings: "statusStrings", + failInfo: "failInfo" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for PKIStatusInfo"); //endregion + //region Get internal properties from parsed schema + + const _status = asn1.result.status; + if (_status.valueBlock.isHexOnly === true || _status.valueBlock.valueDec < 0 || _status.valueBlock.valueDec > 5) throw new Error("PKIStatusInfo \"status\" has invalid value"); + this.status = _status.valueBlock.valueDec; + if ("statusStrings" in asn1.result) this.statusStrings = asn1.result.statusStrings; + if ("failInfo" in asn1.result) this.failInfo = asn1.result.failInfo; //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Create array of output sequence + const outputArray = []; + outputArray.push(new asn1js.Integer({ + value: this.status + })); + + if ("statusStrings" in this) { + outputArray.push(new asn1js.Sequence({ + optional: true, + value: this.statusStrings + })); + } + + if ("failInfo" in this) outputArray.push(this.failInfo); //endregion + //region Construct and return new ASN.1 schema for this object + + return new asn1js.Sequence({ + value: outputArray + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + const _object = { + status: this.status + }; + if ("statusStrings" in this) _object.statusStrings = Array.from(this.statusStrings, element => element.toJSON()); + if ("failInfo" in this) _object.failInfo = this.failInfo.toJSON(); + return _object; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = PKIStatusInfo; + +},{"asn1js":112,"pvutils":113}],70:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _AlgorithmIdentifier = _interopRequireDefault(require("./AlgorithmIdentifier.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC5652 + */ +class PasswordRecipientinfo { + //********************************************************************************** + + /** + * Constructor for PasswordRecipientinfo class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {number} + * @desc version + */ + this.version = (0, _pvutils.getParametersValue)(parameters, "version", PasswordRecipientinfo.defaultValues("version")); + if ("keyDerivationAlgorithm" in parameters) + /** + * @type {AlgorithmIdentifier} + * @desc keyDerivationAlgorithm + */ + this.keyDerivationAlgorithm = (0, _pvutils.getParametersValue)(parameters, "keyDerivationAlgorithm", PasswordRecipientinfo.defaultValues("keyDerivationAlgorithm")); + /** + * @type {AlgorithmIdentifier} + * @desc keyEncryptionAlgorithm + */ + + this.keyEncryptionAlgorithm = (0, _pvutils.getParametersValue)(parameters, "keyEncryptionAlgorithm", PasswordRecipientinfo.defaultValues("keyEncryptionAlgorithm")); + /** + * @type {OctetString} + * @desc encryptedKey + */ + + this.encryptedKey = (0, _pvutils.getParametersValue)(parameters, "encryptedKey", PasswordRecipientinfo.defaultValues("encryptedKey")); + /** + * @type {ArrayBuffer} + * @desc password Password to derive key from + */ + + this.password = (0, _pvutils.getParametersValue)(parameters, "password", PasswordRecipientinfo.defaultValues("password")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "version": + return -1; + + case "keyDerivationAlgorithm": + return new _AlgorithmIdentifier.default(); + + case "keyEncryptionAlgorithm": + return new _AlgorithmIdentifier.default(); + + case "encryptedKey": + return new asn1js.OctetString(); + + case "password": + return new ArrayBuffer(0); + + default: + throw new Error(`Invalid member name for PasswordRecipientinfo class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + + + static compareWithDefault(memberName, memberValue) { + switch (memberName) { + case "version": + return memberValue === -1; + + case "keyDerivationAlgorithm": + case "keyEncryptionAlgorithm": + return memberValue.algorithmId === "" && "algorithmParams" in memberValue === false; + + case "encryptedKey": + return memberValue.isEqual(PasswordRecipientinfo.defaultValues("encryptedKey")); + + case "password": + return memberValue.byteLength === 0; + + default: + throw new Error(`Invalid member name for PasswordRecipientinfo class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * PasswordRecipientInfo ::= SEQUENCE { + * version CMSVersion, -- Always set to 0 + * keyDerivationAlgorithm [0] KeyDerivationAlgorithmIdentifier OPTIONAL, + * keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier, + * encryptedKey EncryptedKey } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [keyDerivationAlgorithm] + * @property {string} [keyEncryptionAlgorithm] + * @property {string} [encryptedKey] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [new asn1js.Integer({ + name: names.version || "" + }), new asn1js.Constructed({ + name: names.keyDerivationAlgorithm || "", + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: _AlgorithmIdentifier.default.schema().valueBlock.value + }), _AlgorithmIdentifier.default.schema(names.keyEncryptionAlgorithm || {}), new asn1js.OctetString({ + name: names.encryptedKey || "" + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["version", "keyDerivationAlgorithm", "keyEncryptionAlgorithm", "encryptedKey"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, PasswordRecipientinfo.schema({ + names: { + version: "version", + keyDerivationAlgorithm: "keyDerivationAlgorithm", + keyEncryptionAlgorithm: { + names: { + blockName: "keyEncryptionAlgorithm" + } + }, + encryptedKey: "encryptedKey" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for PasswordRecipientinfo"); //endregion + //region Get internal properties from parsed schema + + this.version = asn1.result.version.valueBlock.valueDec; + + if ("keyDerivationAlgorithm" in asn1.result) { + this.keyDerivationAlgorithm = new _AlgorithmIdentifier.default({ + schema: new asn1js.Sequence({ + value: asn1.result.keyDerivationAlgorithm.valueBlock.value + }) + }); + } + + this.keyEncryptionAlgorithm = new _AlgorithmIdentifier.default({ + schema: asn1.result.keyEncryptionAlgorithm + }); + this.encryptedKey = asn1.result.encryptedKey; //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Create output array for sequence + const outputArray = []; + outputArray.push(new asn1js.Integer({ + value: this.version + })); + + if ("keyDerivationAlgorithm" in this) { + outputArray.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: this.keyDerivationAlgorithm.toSchema().valueBlock.value + })); + } + + outputArray.push(this.keyEncryptionAlgorithm.toSchema()); + outputArray.push(this.encryptedKey); //endregion + //region Construct and return new ASN.1 schema for this object + + return new asn1js.Sequence({ + value: outputArray + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + return { + version: this.version, + keyDerivationAlgorithm: this.keyDerivationAlgorithm.toJSON(), + keyEncryptionAlgorithm: this.keyEncryptionAlgorithm.toJSON(), + encryptedKey: this.encryptedKey.toJSON() + }; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = PasswordRecipientinfo; + +},{"./AlgorithmIdentifier.js":4,"asn1js":112,"pvutils":113}],71:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC5280 + */ +class PolicyConstraints { + //********************************************************************************** + + /** + * Constructor for PolicyConstraints class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + if ("requireExplicitPolicy" in parameters) + /** + * @type {number} + * @desc requireExplicitPolicy + */ + this.requireExplicitPolicy = (0, _pvutils.getParametersValue)(parameters, "requireExplicitPolicy", PolicyConstraints.defaultValues("requireExplicitPolicy")); + if ("inhibitPolicyMapping" in parameters) + /** + * @type {number} + * @desc Value of the TIME class + */ + this.inhibitPolicyMapping = (0, _pvutils.getParametersValue)(parameters, "inhibitPolicyMapping", PolicyConstraints.defaultValues("inhibitPolicyMapping")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "requireExplicitPolicy": + return 0; + + case "inhibitPolicyMapping": + return 0; + + default: + throw new Error(`Invalid member name for PolicyConstraints class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * PolicyConstraints ::= SEQUENCE { + * requireExplicitPolicy [0] SkipCerts OPTIONAL, + * inhibitPolicyMapping [1] SkipCerts OPTIONAL } + * + * SkipCerts ::= INTEGER (0..MAX) + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [requireExplicitPolicy] + * @property {string} [inhibitPolicyMapping] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [new asn1js.Primitive({ + name: names.requireExplicitPolicy || "", + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + } + }), // IMPLICIT integer value + new asn1js.Primitive({ + name: names.inhibitPolicyMapping || "", + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + + } + }) // IMPLICIT integer value + ] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["requireExplicitPolicy", "inhibitPolicyMapping"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, PolicyConstraints.schema({ + names: { + requireExplicitPolicy: "requireExplicitPolicy", + inhibitPolicyMapping: "inhibitPolicyMapping" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for PolicyConstraints"); //endregion + //region Get internal properties from parsed schema + + if ("requireExplicitPolicy" in asn1.result) { + const field1 = asn1.result.requireExplicitPolicy; + field1.idBlock.tagClass = 1; // UNIVERSAL + + field1.idBlock.tagNumber = 2; // INTEGER + + const ber1 = field1.toBER(false); + const int1 = asn1js.fromBER(ber1); + this.requireExplicitPolicy = int1.result.valueBlock.valueDec; + } + + if ("inhibitPolicyMapping" in asn1.result) { + const field2 = asn1.result.inhibitPolicyMapping; + field2.idBlock.tagClass = 1; // UNIVERSAL + + field2.idBlock.tagNumber = 2; // INTEGER + + const ber2 = field2.toBER(false); + const int2 = asn1js.fromBER(ber2); + this.inhibitPolicyMapping = int2.result.valueBlock.valueDec; + } //endregion + + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Create correct values for output sequence + const outputArray = []; + + if ("requireExplicitPolicy" in this) { + const int1 = new asn1js.Integer({ + value: this.requireExplicitPolicy + }); + int1.idBlock.tagClass = 3; // CONTEXT-SPECIFIC + + int1.idBlock.tagNumber = 0; // [0] + + outputArray.push(int1); + } + + if ("inhibitPolicyMapping" in this) { + const int2 = new asn1js.Integer({ + value: this.inhibitPolicyMapping + }); + int2.idBlock.tagClass = 3; // CONTEXT-SPECIFIC + + int2.idBlock.tagNumber = 1; // [1] + + outputArray.push(int2); + } //endregion + //region Construct and return new ASN.1 schema for this object + + + return new asn1js.Sequence({ + value: outputArray + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + const object = {}; + if ("requireExplicitPolicy" in this) object.requireExplicitPolicy = this.requireExplicitPolicy; + if ("inhibitPolicyMapping" in this) object.inhibitPolicyMapping = this.inhibitPolicyMapping; + return object; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = PolicyConstraints; + +},{"asn1js":112,"pvutils":113}],72:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _PolicyQualifierInfo = _interopRequireDefault(require("./PolicyQualifierInfo.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC5280 + */ +class PolicyInformation { + //********************************************************************************** + + /** + * Constructor for PolicyInformation class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {string} + * @desc policyIdentifier + */ + this.policyIdentifier = (0, _pvutils.getParametersValue)(parameters, "policyIdentifier", PolicyInformation.defaultValues("policyIdentifier")); + if ("policyQualifiers" in parameters) + /** + * @type {Array.} + * @desc Value of the TIME class + */ + this.policyQualifiers = (0, _pvutils.getParametersValue)(parameters, "policyQualifiers", PolicyInformation.defaultValues("policyQualifiers")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "policyIdentifier": + return ""; + + case "policyQualifiers": + return []; + + default: + throw new Error(`Invalid member name for PolicyInformation class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * PolicyInformation ::= SEQUENCE { + * policyIdentifier CertPolicyId, + * policyQualifiers SEQUENCE SIZE (1..MAX) OF + * PolicyQualifierInfo OPTIONAL } + * + * CertPolicyId ::= OBJECT IDENTIFIER + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [policyIdentifier] + * @property {string} [policyQualifiers] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [new asn1js.ObjectIdentifier({ + name: names.policyIdentifier || "" + }), new asn1js.Sequence({ + optional: true, + value: [new asn1js.Repeated({ + name: names.policyQualifiers || "", + value: _PolicyQualifierInfo.default.schema() + })] + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["policyIdentifier", "policyQualifiers"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, PolicyInformation.schema({ + names: { + policyIdentifier: "policyIdentifier", + policyQualifiers: "policyQualifiers" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for PolicyInformation"); //endregion + //region Get internal properties from parsed schema + + this.policyIdentifier = asn1.result.policyIdentifier.valueBlock.toString(); + if ("policyQualifiers" in asn1.result) this.policyQualifiers = Array.from(asn1.result.policyQualifiers, element => new _PolicyQualifierInfo.default({ + schema: element + })); //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Create array for output sequence + const outputArray = []; + outputArray.push(new asn1js.ObjectIdentifier({ + value: this.policyIdentifier + })); + + if ("policyQualifiers" in this) { + outputArray.push(new asn1js.Sequence({ + value: Array.from(this.policyQualifiers, element => element.toSchema()) + })); + } //endregion + //region Construct and return new ASN.1 schema for this object + + + return new asn1js.Sequence({ + value: outputArray + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + const object = { + policyIdentifier: this.policyIdentifier + }; + if ("policyQualifiers" in this) object.policyQualifiers = Array.from(this.policyQualifiers, element => element.toJSON()); + return object; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = PolicyInformation; + +},{"./PolicyQualifierInfo.js":75,"asn1js":112,"pvutils":113}],73:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC5280 + */ +class PolicyMapping { + //********************************************************************************** + + /** + * Constructor for PolicyMapping class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {string} + * @desc issuerDomainPolicy + */ + this.issuerDomainPolicy = (0, _pvutils.getParametersValue)(parameters, "issuerDomainPolicy", PolicyMapping.defaultValues("issuerDomainPolicy")); + /** + * @type {string} + * @desc subjectDomainPolicy + */ + + this.subjectDomainPolicy = (0, _pvutils.getParametersValue)(parameters, "subjectDomainPolicy", PolicyMapping.defaultValues("subjectDomainPolicy")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "issuerDomainPolicy": + return ""; + + case "subjectDomainPolicy": + return ""; + + default: + throw new Error(`Invalid member name for PolicyMapping class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * PolicyMapping ::= SEQUENCE { + * issuerDomainPolicy CertPolicyId, + * subjectDomainPolicy CertPolicyId } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [issuerDomainPolicy] + * @property {string} [subjectDomainPolicy] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [new asn1js.ObjectIdentifier({ + name: names.issuerDomainPolicy || "" + }), new asn1js.ObjectIdentifier({ + name: names.subjectDomainPolicy || "" + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["issuerDomainPolicy", "subjectDomainPolicy"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, PolicyMapping.schema({ + names: { + issuerDomainPolicy: "issuerDomainPolicy", + subjectDomainPolicy: "subjectDomainPolicy" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for PolicyMapping"); //endregion + //region Get internal properties from parsed schema + + this.issuerDomainPolicy = asn1.result.issuerDomainPolicy.valueBlock.toString(); + this.subjectDomainPolicy = asn1.result.subjectDomainPolicy.valueBlock.toString(); //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Construct and return new ASN.1 schema for this object + return new asn1js.Sequence({ + value: [new asn1js.ObjectIdentifier({ + value: this.issuerDomainPolicy + }), new asn1js.ObjectIdentifier({ + value: this.subjectDomainPolicy + })] + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + return { + issuerDomainPolicy: this.issuerDomainPolicy, + subjectDomainPolicy: this.subjectDomainPolicy + }; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = PolicyMapping; + +},{"asn1js":112,"pvutils":113}],74:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _PolicyMapping = _interopRequireDefault(require("./PolicyMapping.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC5280 + */ +class PolicyMappings { + //********************************************************************************** + + /** + * Constructor for PolicyMappings class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {Array.} + * @desc mappings + */ + this.mappings = (0, _pvutils.getParametersValue)(parameters, "mappings", PolicyMappings.defaultValues("mappings")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "mappings": + return []; + + default: + throw new Error(`Invalid member name for PolicyMappings class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * PolicyMappings ::= SEQUENCE SIZE (1..MAX) OF PolicyMapping + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [utcTimeName] Name for "utcTimeName" choice + * @property {string} [generalTimeName] Name for "generalTimeName" choice + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [new asn1js.Repeated({ + name: names.mappings || "", + value: _PolicyMapping.default.schema() + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["mappings"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, PolicyMappings.schema({ + names: { + mappings: "mappings" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for PolicyMappings"); //endregion + //region Get internal properties from parsed schema + + this.mappings = Array.from(asn1.result.mappings, element => new _PolicyMapping.default({ + schema: element + })); //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Construct and return new ASN.1 schema for this object + return new asn1js.Sequence({ + value: Array.from(this.mappings, element => element.toSchema()) + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + return { + mappings: Array.from(this.mappings, element => element.toJSON()) + }; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = PolicyMappings; + +},{"./PolicyMapping.js":73,"asn1js":112,"pvutils":113}],75:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC5280 + */ +class PolicyQualifierInfo { + //********************************************************************************** + + /** + * Constructor for PolicyQualifierInfo class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {string} + * @desc policyQualifierId + */ + this.policyQualifierId = (0, _pvutils.getParametersValue)(parameters, "policyQualifierId", PolicyQualifierInfo.defaultValues("policyQualifierId")); + /** + * @type {Object} + * @desc qualifier + */ + + this.qualifier = (0, _pvutils.getParametersValue)(parameters, "qualifier", PolicyQualifierInfo.defaultValues("qualifier")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "policyQualifierId": + return ""; + + case "qualifier": + return new asn1js.Any(); + + default: + throw new Error(`Invalid member name for PolicyQualifierInfo class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * PolicyQualifierInfo ::= SEQUENCE { + * policyQualifierId PolicyQualifierId, + * qualifier ANY DEFINED BY policyQualifierId } + * + * id-qt OBJECT IDENTIFIER ::= { id-pkix 2 } + * id-qt-cps OBJECT IDENTIFIER ::= { id-qt 1 } + * id-qt-unotice OBJECT IDENTIFIER ::= { id-qt 2 } + * + * PolicyQualifierId ::= OBJECT IDENTIFIER ( id-qt-cps | id-qt-unotice ) + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [policyQualifierId] + * @property {string} [qualifier] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [new asn1js.ObjectIdentifier({ + name: names.policyQualifierId || "" + }), new asn1js.Any({ + name: names.qualifier || "" + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["policyQualifierId", "qualifier"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, PolicyQualifierInfo.schema({ + names: { + policyQualifierId: "policyQualifierId", + qualifier: "qualifier" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for PolicyQualifierInfo"); //endregion + //region Get internal properties from parsed schema + + this.policyQualifierId = asn1.result.policyQualifierId.valueBlock.toString(); + this.qualifier = asn1.result.qualifier; //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Construct and return new ASN.1 schema for this object + return new asn1js.Sequence({ + value: [new asn1js.ObjectIdentifier({ + value: this.policyQualifierId + }), this.qualifier] + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + return { + policyQualifierId: this.policyQualifierId, + qualifier: this.qualifier.toJSON() + }; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = PolicyQualifierInfo; + +},{"asn1js":112,"pvutils":113}],76:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _AlgorithmIdentifier = _interopRequireDefault(require("./AlgorithmIdentifier.js")); + +var _Attribute = _interopRequireDefault(require("./Attribute.js")); + +var _ECPrivateKey = _interopRequireDefault(require("./ECPrivateKey.js")); + +var _RSAPrivateKey = _interopRequireDefault(require("./RSAPrivateKey.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC5208 + */ +class PrivateKeyInfo { + //********************************************************************************** + + /** + * Constructor for PrivateKeyInfo class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {number} + * @desc version + */ + this.version = (0, _pvutils.getParametersValue)(parameters, "version", PrivateKeyInfo.defaultValues("version")); + /** + * @type {AlgorithmIdentifier} + * @desc privateKeyAlgorithm + */ + + this.privateKeyAlgorithm = (0, _pvutils.getParametersValue)(parameters, "privateKeyAlgorithm", PrivateKeyInfo.defaultValues("privateKeyAlgorithm")); + /** + * @type {OctetString} + * @desc privateKey + */ + + this.privateKey = (0, _pvutils.getParametersValue)(parameters, "privateKey", PrivateKeyInfo.defaultValues("privateKey")); + if ("attributes" in parameters) + /** + * @type {Array.} + * @desc attributes + */ + this.attributes = (0, _pvutils.getParametersValue)(parameters, "attributes", PrivateKeyInfo.defaultValues("attributes")); + if ("parsedKey" in parameters) + /** + * @type {ECPrivateKey|RSAPrivateKey} + * @desc Parsed public key value + */ + this.parsedKey = (0, _pvutils.getParametersValue)(parameters, "parsedKey", PrivateKeyInfo.defaultValues("parsedKey")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + //region If input argument array contains "json" for this object + + if ("json" in parameters) this.fromJSON(parameters.json); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "version": + return 0; + + case "privateKeyAlgorithm": + return new _AlgorithmIdentifier.default(); + + case "privateKey": + return new asn1js.OctetString(); + + case "attributes": + return []; + + case "parsedKey": + return {}; + + default: + throw new Error(`Invalid member name for PrivateKeyInfo class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * PrivateKeyInfo ::= SEQUENCE { + * version Version, + * privateKeyAlgorithm AlgorithmIdentifier {{PrivateKeyAlgorithms}}, + * privateKey PrivateKey, + * attributes [0] Attributes OPTIONAL } + * + * Version ::= INTEGER {v1(0)} (v1,...) + * + * PrivateKey ::= OCTET STRING + * + * Attributes ::= SET OF Attribute + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [version] + * @property {string} [privateKeyAlgorithm] + * @property {string} [privateKey] + * @property {string} [attributes] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [new asn1js.Integer({ + name: names.version || "" + }), _AlgorithmIdentifier.default.schema(names.privateKeyAlgorithm || {}), new asn1js.OctetString({ + name: names.privateKey || "" + }), new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: [new asn1js.Repeated({ + name: names.attributes || "", + value: _Attribute.default.schema() + })] + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["version", "privateKeyAlgorithm", "privateKey", "attributes"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, PrivateKeyInfo.schema({ + names: { + version: "version", + privateKeyAlgorithm: { + names: { + blockName: "privateKeyAlgorithm" + } + }, + privateKey: "privateKey", + attributes: "attributes" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for PrivateKeyInfo"); //endregion + //region Get internal properties from parsed schema + + this.version = asn1.result.version.valueBlock.valueDec; + this.privateKeyAlgorithm = new _AlgorithmIdentifier.default({ + schema: asn1.result.privateKeyAlgorithm + }); + this.privateKey = asn1.result.privateKey; + if ("attributes" in asn1.result) this.attributes = Array.from(asn1.result.attributes, element => new _Attribute.default({ + schema: element + })); + + switch (this.privateKeyAlgorithm.algorithmId) { + case "1.2.840.113549.1.1.1": + // RSA + { + const privateKeyASN1 = asn1js.fromBER(this.privateKey.valueBlock.valueHex); + if (privateKeyASN1.offset !== -1) this.parsedKey = new _RSAPrivateKey.default({ + schema: privateKeyASN1.result + }); + } + break; + + case "1.2.840.10045.2.1": + // ECDSA + if ("algorithmParams" in this.privateKeyAlgorithm) { + if (this.privateKeyAlgorithm.algorithmParams instanceof asn1js.ObjectIdentifier) { + const privateKeyASN1 = asn1js.fromBER(this.privateKey.valueBlock.valueHex); + + if (privateKeyASN1.offset !== -1) { + this.parsedKey = new _ECPrivateKey.default({ + namedCurve: this.privateKeyAlgorithm.algorithmParams.valueBlock.toString(), + schema: privateKeyASN1.result + }); + } + } + } + + break; + + default: + } //endregion + + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Create array for output sequence + const outputArray = [new asn1js.Integer({ + value: this.version + }), this.privateKeyAlgorithm.toSchema(), this.privateKey]; + + if ("attributes" in this) { + outputArray.push(new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: Array.from(this.attributes, element => element.toSchema()) + })); + } //endregion + //region Construct and return new ASN.1 schema for this object + + + return new asn1js.Sequence({ + value: outputArray + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + //region Return common value in case we do not have enough info fo making JWK + if ("parsedKey" in this === false) { + const object = { + version: this.version, + privateKeyAlgorithm: this.privateKeyAlgorithm.toJSON(), + privateKey: this.privateKey.toJSON() + }; + if ("attributes" in this) object.attributes = Array.from(this.attributes, element => element.toJSON()); + return object; + } //endregion + //region Making JWK + + + const jwk = {}; + + switch (this.privateKeyAlgorithm.algorithmId) { + case "1.2.840.10045.2.1": + // ECDSA + jwk.kty = "EC"; + break; + + case "1.2.840.113549.1.1.1": + // RSA + jwk.kty = "RSA"; + break; + + default: + } + + const publicKeyJWK = this.parsedKey.toJSON(); + + for (var _i = 0, _Object$keys = Object.keys(publicKeyJWK); _i < _Object$keys.length; _i++) { + const key = _Object$keys[_i]; + jwk[key] = publicKeyJWK[key]; + } + + return jwk; //endregion + } //********************************************************************************** + + /** + * Convert JSON value into current object + * @param {Object} json + */ + + + fromJSON(json) { + if ("kty" in json) { + switch (json.kty.toUpperCase()) { + case "EC": + this.parsedKey = new _ECPrivateKey.default({ + json + }); + this.privateKeyAlgorithm = new _AlgorithmIdentifier.default({ + algorithmId: "1.2.840.10045.2.1", + algorithmParams: new asn1js.ObjectIdentifier({ + value: this.parsedKey.namedCurve + }) + }); + break; + + case "RSA": + this.parsedKey = new _RSAPrivateKey.default({ + json + }); + this.privateKeyAlgorithm = new _AlgorithmIdentifier.default({ + algorithmId: "1.2.840.113549.1.1.1", + algorithmParams: new asn1js.Null() + }); + break; + + default: + throw new Error(`Invalid value for "kty" parameter: ${json.kty}`); + } + + this.privateKey = new asn1js.OctetString({ + valueHex: this.parsedKey.toSchema().toBER(false) + }); + } + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = PrivateKeyInfo; + +},{"./AlgorithmIdentifier.js":4,"./Attribute.js":6,"./ECPrivateKey.js":31,"./RSAPrivateKey.js":81,"asn1js":112,"pvutils":113}],77:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC5280 + */ +class PrivateKeyUsagePeriod { + //********************************************************************************** + + /** + * Constructor for PrivateKeyUsagePeriod class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + if ("notBefore" in parameters) + /** + * @type {Date} + * @desc notBefore + */ + this.notBefore = (0, _pvutils.getParametersValue)(parameters, "notBefore", PrivateKeyUsagePeriod.defaultValues("notBefore")); + if ("notAfter" in parameters) + /** + * @type {Date} + * @desc notAfter + */ + this.notAfter = (0, _pvutils.getParametersValue)(parameters, "notAfter", PrivateKeyUsagePeriod.defaultValues("notAfter")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "notBefore": + return new Date(); + + case "notAfter": + return new Date(); + + default: + throw new Error(`Invalid member name for PrivateKeyUsagePeriod class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * PrivateKeyUsagePeriod OID ::= 2.5.29.16 + * + * PrivateKeyUsagePeriod ::= SEQUENCE { + * notBefore [0] GeneralizedTime OPTIONAL, + * notAfter [1] GeneralizedTime OPTIONAL } + * -- either notBefore or notAfter MUST be present + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [notBefore] + * @property {string} [notAfter] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [new asn1js.Primitive({ + name: names.notBefore || "", + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + } + }), new asn1js.Primitive({ + name: names.notAfter || "", + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + + } + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["notBefore", "notAfter"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, PrivateKeyUsagePeriod.schema({ + names: { + notBefore: "notBefore", + notAfter: "notAfter" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for PrivateKeyUsagePeriod"); //endregion + //region Get internal properties from parsed schema + + if ("notBefore" in asn1.result) { + const localNotBefore = new asn1js.GeneralizedTime(); + localNotBefore.fromBuffer(asn1.result.notBefore.valueBlock.valueHex); + this.notBefore = localNotBefore.toDate(); + } + + if ("notAfter" in asn1.result) { + const localNotAfter = new asn1js.GeneralizedTime({ + valueHex: asn1.result.notAfter.valueBlock.valueHex + }); + localNotAfter.fromBuffer(asn1.result.notAfter.valueBlock.valueHex); + this.notAfter = localNotAfter.toDate(); + } //endregion + + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Create array for output sequence + const outputArray = []; + + if ("notBefore" in this) { + outputArray.push(new asn1js.Primitive({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + valueHex: new asn1js.GeneralizedTime({ + valueDate: this.notBefore + }).valueBlock.valueHex + })); + } + + if ("notAfter" in this) { + outputArray.push(new asn1js.Primitive({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + + }, + valueHex: new asn1js.GeneralizedTime({ + valueDate: this.notAfter + }).valueBlock.valueHex + })); + } //endregion + //region Construct and return new ASN.1 schema for this object + + + return new asn1js.Sequence({ + value: outputArray + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + const object = {}; + if ("notBefore" in this) object.notBefore = this.notBefore; + if ("notAfter" in this) object.notAfter = this.notAfter; + return object; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = PrivateKeyUsagePeriod; + +},{"asn1js":112,"pvutils":113}],78:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _common = require("./common.js"); + +var _AlgorithmIdentifier = _interopRequireDefault(require("./AlgorithmIdentifier.js")); + +var _ECPublicKey = _interopRequireDefault(require("./ECPublicKey.js")); + +var _RSAPublicKey = _interopRequireDefault(require("./RSAPublicKey.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC5280 + */ +class PublicKeyInfo { + //********************************************************************************** + + /** + * Constructor for PublicKeyInfo class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {AlgorithmIdentifier} + * @desc Algorithm identifier + */ + this.algorithm = (0, _pvutils.getParametersValue)(parameters, "algorithm", PublicKeyInfo.defaultValues("algorithm")); + /** + * @type {BitString} + * @desc Subject public key value + */ + + this.subjectPublicKey = (0, _pvutils.getParametersValue)(parameters, "subjectPublicKey", PublicKeyInfo.defaultValues("subjectPublicKey")); + if ("parsedKey" in parameters) + /** + * @type {ECPublicKey|RSAPublicKey} + * @desc Parsed public key value + */ + this.parsedKey = (0, _pvutils.getParametersValue)(parameters, "parsedKey", PublicKeyInfo.defaultValues("parsedKey")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + //region If input argument array contains "json" for this object + + if ("json" in parameters) this.fromJSON(parameters.json); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "algorithm": + return new _AlgorithmIdentifier.default(); + + case "subjectPublicKey": + return new asn1js.BitString(); + + default: + throw new Error(`Invalid member name for PublicKeyInfo class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * SubjectPublicKeyInfo ::= Sequence { + * algorithm AlgorithmIdentifier, + * subjectPublicKey BIT STRING } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [algorithm] + * @property {string} [subjectPublicKey] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [_AlgorithmIdentifier.default.schema(names.algorithm || {}), new asn1js.BitString({ + name: names.subjectPublicKey || "" + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["algorithm", "subjectPublicKey"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, PublicKeyInfo.schema({ + names: { + algorithm: { + names: { + blockName: "algorithm" + } + }, + subjectPublicKey: "subjectPublicKey" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for PublicKeyInfo"); //endregion + //region Get internal properties from parsed schema + + this.algorithm = new _AlgorithmIdentifier.default({ + schema: asn1.result.algorithm + }); + this.subjectPublicKey = asn1.result.subjectPublicKey; + + switch (this.algorithm.algorithmId) { + case "1.2.840.10045.2.1": + // ECDSA + if ("algorithmParams" in this.algorithm) { + if (this.algorithm.algorithmParams instanceof asn1js.ObjectIdentifier) { + try { + this.parsedKey = new _ECPublicKey.default({ + namedCurve: this.algorithm.algorithmParams.valueBlock.toString(), + schema: this.subjectPublicKey.valueBlock.valueHex + }); + } catch (ex) {} // Could be a problems during recognision of internal public key data here. Let's ignore them. + + } + } + + break; + + case "1.2.840.113549.1.1.1": + // RSA + { + const publicKeyASN1 = asn1js.fromBER(this.subjectPublicKey.valueBlock.valueHex); + + if (publicKeyASN1.offset !== -1) { + try { + this.parsedKey = new _RSAPublicKey.default({ + schema: publicKeyASN1.result + }); + } catch (ex) {} // Could be a problems during recognision of internal public key data here. Let's ignore them. + + } + } + break; + + default: + } //endregion + + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Construct and return new ASN.1 schema for this object + return new asn1js.Sequence({ + value: [this.algorithm.toSchema(), this.subjectPublicKey] + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + //region Return common value in case we do not have enough info fo making JWK + if ("parsedKey" in this === false) { + return { + algorithm: this.algorithm.toJSON(), + subjectPublicKey: this.subjectPublicKey.toJSON() + }; + } //endregion + //region Making JWK + + + const jwk = {}; + + switch (this.algorithm.algorithmId) { + case "1.2.840.10045.2.1": + // ECDSA + jwk.kty = "EC"; + break; + + case "1.2.840.113549.1.1.1": + // RSA + jwk.kty = "RSA"; + break; + + default: + } + + const publicKeyJWK = this.parsedKey.toJSON(); + + for (var _i = 0, _Object$keys = Object.keys(publicKeyJWK); _i < _Object$keys.length; _i++) { + const key = _Object$keys[_i]; + jwk[key] = publicKeyJWK[key]; + } + + return jwk; //endregion + } //********************************************************************************** + + /** + * Convert JSON value into current object + * @param {Object} json + */ + + + fromJSON(json) { + if ("kty" in json) { + switch (json.kty.toUpperCase()) { + case "EC": + this.parsedKey = new _ECPublicKey.default({ + json + }); + this.algorithm = new _AlgorithmIdentifier.default({ + algorithmId: "1.2.840.10045.2.1", + algorithmParams: new asn1js.ObjectIdentifier({ + value: this.parsedKey.namedCurve + }) + }); + break; + + case "RSA": + this.parsedKey = new _RSAPublicKey.default({ + json + }); + this.algorithm = new _AlgorithmIdentifier.default({ + algorithmId: "1.2.840.113549.1.1.1", + algorithmParams: new asn1js.Null() + }); + break; + + default: + throw new Error(`Invalid value for "kty" parameter: ${json.kty}`); + } + + this.subjectPublicKey = new asn1js.BitString({ + valueHex: this.parsedKey.toSchema().toBER(false) + }); + } + } //********************************************************************************** + + + importKey(publicKey) { + //region Initial variables + let sequence = Promise.resolve(); + + const _this = this; //endregion + //region Initial check + + + if (typeof publicKey === "undefined") return Promise.reject("Need to provide publicKey input parameter"); //endregion + //region Get a "crypto" extension + + const crypto = (0, _common.getCrypto)(); + if (typeof crypto === "undefined") return Promise.reject("Unable to create WebCrypto object"); //endregion + //region Export public key + + sequence = sequence.then(() => crypto.exportKey("spki", publicKey)); //endregion + //region Initialize internal variables by parsing exported value + + sequence = sequence.then( + /** + * @param {ArrayBuffer} exportedKey + */ + exportedKey => { + const asn1 = asn1js.fromBER(exportedKey); + + try { + _this.fromSchema(asn1.result); + } catch (exception) { + return Promise.reject("Error during initializing object from schema"); + } + + return undefined; + }, error => Promise.reject(`Error during exporting public key: ${error}`)); //endregion + + return sequence; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = PublicKeyInfo; + +},{"./AlgorithmIdentifier.js":4,"./ECPublicKey.js":32,"./RSAPublicKey.js":82,"./common.js":110,"asn1js":112,"pvutils":113}],79:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = exports.QCStatement = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC3739 + */ +class QCStatement { + //********************************************************************************** + + /** + * Constructor for QCStatement class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {string} + */ + this.id = (0, _pvutils.getParametersValue)(parameters, "id", QCStatement.defaultValues("id")); + + if ("type" in parameters) { + /** + * @type {*} Any data described by "id" + */ + this.type = (0, _pvutils.getParametersValue)(parameters, "type", QCStatement.defaultValues("type")); + } //endregion + //region If input argument array contains "schema" for this object + + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "id": + return ""; + + case "type": + return new asn1js.Null(); + + default: + throw new Error(`Invalid member name for QCStatement class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + + + static compareWithDefault(memberName, memberValue) { + switch (memberName) { + case "id": + return memberValue === ""; + + case "type": + return memberValue instanceof asn1js.Null; + + default: + throw new Error(`Invalid member name for QCStatement class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * QCStatement ::= SEQUENCE { + * statementId QC-STATEMENT.&id({SupportedStatements}), + * statementInfo QC-STATEMENT.&Type({SupportedStatements}{@statementId}) OPTIONAL + * } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [id] + * @property {string} [type] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [new asn1js.ObjectIdentifier({ + name: names.id || "" + }), new asn1js.Any({ + name: names.type || "", + optional: true + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["id", "type"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, QCStatement.schema({ + names: { + id: "id", + type: "type" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for QCStatement"); //endregion + //region Get internal properties from parsed schema + + this.id = asn1.result.id.valueBlock.toString(); + if ("type" in asn1.result) this.type = asn1.result.type; //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + const value = [new asn1js.ObjectIdentifier({ + value: this.id + })]; + if ("type" in this) value.push(this.type); //region Construct and return new ASN.1 schema for this object + + return new asn1js.Sequence({ + value + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + const object = { + id: this.id + }; + if ("type" in this) object.type = this.type.toJSON(); + return object; + } //********************************************************************************** + + +} //************************************************************************************** + +/** + * Class from RFC3739 + */ + + +exports.QCStatement = QCStatement; + +class QCStatements { + //********************************************************************************** + + /** + * Constructor for QCStatements class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {Array} + */ + this.values = (0, _pvutils.getParametersValue)(parameters, "values", QCStatements.defaultValues("values")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "values": + return []; + + default: + throw new Error(`Invalid member name for QCStatements class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + + + static compareWithDefault(memberName, memberValue) { + switch (memberName) { + case "values": + return memberValue.length === 0; + + default: + throw new Error(`Invalid member name for QCStatements class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * QCStatements ::= SEQUENCE OF QCStatement + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [values] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [new asn1js.Repeated({ + name: names.values || "", + value: QCStatement.schema(names.value || {}) + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["values"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, QCStatements.schema({ + names: { + values: "values" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for QCStatements"); //endregion + //region Get internal properties from parsed schema + + this.values = Array.from(asn1.result.values, element => new QCStatement({ + schema: element + })); //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Construct and return new ASN.1 schema for this object + return new asn1js.Sequence({ + value: Array.from(this.values, element => element.toSchema()) + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + return { + extensions: Array.from(this.values, element => element.toJSON()) + }; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = QCStatements; + +},{"asn1js":112,"pvutils":113}],80:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _AlgorithmIdentifier = _interopRequireDefault(require("./AlgorithmIdentifier.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC3447 + */ +class RSAESOAEPParams { + //********************************************************************************** + + /** + * Constructor for RSAESOAEPParams class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {AlgorithmIdentifier} + * @desc hashAlgorithm + */ + this.hashAlgorithm = (0, _pvutils.getParametersValue)(parameters, "hashAlgorithm", RSAESOAEPParams.defaultValues("hashAlgorithm")); + /** + * @type {AlgorithmIdentifier} + * @desc maskGenAlgorithm + */ + + this.maskGenAlgorithm = (0, _pvutils.getParametersValue)(parameters, "maskGenAlgorithm", RSAESOAEPParams.defaultValues("maskGenAlgorithm")); + /** + * @type {AlgorithmIdentifier} + * @desc pSourceAlgorithm + */ + + this.pSourceAlgorithm = (0, _pvutils.getParametersValue)(parameters, "pSourceAlgorithm", RSAESOAEPParams.defaultValues("pSourceAlgorithm")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "hashAlgorithm": + return new _AlgorithmIdentifier.default({ + algorithmId: "1.3.14.3.2.26", + // SHA-1 + algorithmParams: new asn1js.Null() + }); + + case "maskGenAlgorithm": + return new _AlgorithmIdentifier.default({ + algorithmId: "1.2.840.113549.1.1.8", + // MGF1 + algorithmParams: new _AlgorithmIdentifier.default({ + algorithmId: "1.3.14.3.2.26", + // SHA-1 + algorithmParams: new asn1js.Null() + }).toSchema() + }); + + case "pSourceAlgorithm": + return new _AlgorithmIdentifier.default({ + algorithmId: "1.2.840.113549.1.1.9", + // id-pSpecified + algorithmParams: new asn1js.OctetString({ + valueHex: new Uint8Array([0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09]).buffer + }) // SHA-1 hash of empty string + + }); + + default: + throw new Error(`Invalid member name for RSAESOAEPParams class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * RSAES-OAEP-params ::= SEQUENCE { + * hashAlgorithm [0] HashAlgorithm DEFAULT sha1, + * maskGenAlgorithm [1] MaskGenAlgorithm DEFAULT mgf1SHA1, + * pSourceAlgorithm [2] PSourceAlgorithm DEFAULT pSpecifiedEmpty + * } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [hashAlgorithm] + * @property {string} [maskGenAlgorithm] + * @property {string} [pSourceAlgorithm] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [new asn1js.Constructed({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + optional: true, + value: [_AlgorithmIdentifier.default.schema(names.hashAlgorithm || {})] + }), new asn1js.Constructed({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + + }, + optional: true, + value: [_AlgorithmIdentifier.default.schema(names.maskGenAlgorithm || {})] + }), new asn1js.Constructed({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 2 // [2] + + }, + optional: true, + value: [_AlgorithmIdentifier.default.schema(names.pSourceAlgorithm || {})] + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["hashAlgorithm", "maskGenAlgorithm", "pSourceAlgorithm"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, RSAESOAEPParams.schema({ + names: { + hashAlgorithm: { + names: { + blockName: "hashAlgorithm" + } + }, + maskGenAlgorithm: { + names: { + blockName: "maskGenAlgorithm" + } + }, + pSourceAlgorithm: { + names: { + blockName: "pSourceAlgorithm" + } + } + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for RSAESOAEPParams"); //endregion + //region Get internal properties from parsed schema + + if ("hashAlgorithm" in asn1.result) this.hashAlgorithm = new _AlgorithmIdentifier.default({ + schema: asn1.result.hashAlgorithm + }); + if ("maskGenAlgorithm" in asn1.result) this.maskGenAlgorithm = new _AlgorithmIdentifier.default({ + schema: asn1.result.maskGenAlgorithm + }); + if ("pSourceAlgorithm" in asn1.result) this.pSourceAlgorithm = new _AlgorithmIdentifier.default({ + schema: asn1.result.pSourceAlgorithm + }); //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Create array for output sequence + const outputArray = []; + + if (!this.hashAlgorithm.isEqual(RSAESOAEPParams.defaultValues("hashAlgorithm"))) { + outputArray.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: [this.hashAlgorithm.toSchema()] + })); + } + + if (!this.maskGenAlgorithm.isEqual(RSAESOAEPParams.defaultValues("maskGenAlgorithm"))) { + outputArray.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + + }, + value: [this.maskGenAlgorithm.toSchema()] + })); + } + + if (!this.pSourceAlgorithm.isEqual(RSAESOAEPParams.defaultValues("pSourceAlgorithm"))) { + outputArray.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 2 // [2] + + }, + value: [this.pSourceAlgorithm.toSchema()] + })); + } //endregion + //region Construct and return new ASN.1 schema for this object + + + return new asn1js.Sequence({ + value: outputArray + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + const object = {}; + if (!this.hashAlgorithm.isEqual(RSAESOAEPParams.defaultValues("hashAlgorithm"))) object.hashAlgorithm = this.hashAlgorithm.toJSON(); + if (!this.maskGenAlgorithm.isEqual(RSAESOAEPParams.defaultValues("maskGenAlgorithm"))) object.maskGenAlgorithm = this.maskGenAlgorithm.toJSON(); + if (!this.pSourceAlgorithm.isEqual(RSAESOAEPParams.defaultValues("pSourceAlgorithm"))) object.pSourceAlgorithm = this.pSourceAlgorithm.toJSON(); + return object; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = RSAESOAEPParams; + +},{"./AlgorithmIdentifier.js":4,"asn1js":112,"pvutils":113}],81:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _OtherPrimeInfo = _interopRequireDefault(require("./OtherPrimeInfo.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC3447 + */ +class RSAPrivateKey { + //********************************************************************************** + + /** + * Constructor for RSAPrivateKey class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {number} + * @desc version + */ + this.version = (0, _pvutils.getParametersValue)(parameters, "version", RSAPrivateKey.defaultValues("version")); + /** + * @type {Integer} + * @desc modulus + */ + + this.modulus = (0, _pvutils.getParametersValue)(parameters, "modulus", RSAPrivateKey.defaultValues("modulus")); + /** + * @type {Integer} + * @desc publicExponent + */ + + this.publicExponent = (0, _pvutils.getParametersValue)(parameters, "publicExponent", RSAPrivateKey.defaultValues("publicExponent")); + /** + * @type {Integer} + * @desc privateExponent + */ + + this.privateExponent = (0, _pvutils.getParametersValue)(parameters, "privateExponent", RSAPrivateKey.defaultValues("privateExponent")); + /** + * @type {Integer} + * @desc prime1 + */ + + this.prime1 = (0, _pvutils.getParametersValue)(parameters, "prime1", RSAPrivateKey.defaultValues("prime1")); + /** + * @type {Integer} + * @desc prime2 + */ + + this.prime2 = (0, _pvutils.getParametersValue)(parameters, "prime2", RSAPrivateKey.defaultValues("prime2")); + /** + * @type {Integer} + * @desc exponent1 + */ + + this.exponent1 = (0, _pvutils.getParametersValue)(parameters, "exponent1", RSAPrivateKey.defaultValues("exponent1")); + /** + * @type {Integer} + * @desc exponent2 + */ + + this.exponent2 = (0, _pvutils.getParametersValue)(parameters, "exponent2", RSAPrivateKey.defaultValues("exponent2")); + /** + * @type {Integer} + * @desc coefficient + */ + + this.coefficient = (0, _pvutils.getParametersValue)(parameters, "coefficient", RSAPrivateKey.defaultValues("coefficient")); + if ("otherPrimeInfos" in parameters) + /** + * @type {Array.} + * @desc otherPrimeInfos + */ + this.otherPrimeInfos = (0, _pvutils.getParametersValue)(parameters, "otherPrimeInfos", RSAPrivateKey.defaultValues("otherPrimeInfos")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + //region If input argument array contains "json" for this object + + if ("json" in parameters) this.fromJSON(parameters.json); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "version": + return 0; + + case "modulus": + return new asn1js.Integer(); + + case "publicExponent": + return new asn1js.Integer(); + + case "privateExponent": + return new asn1js.Integer(); + + case "prime1": + return new asn1js.Integer(); + + case "prime2": + return new asn1js.Integer(); + + case "exponent1": + return new asn1js.Integer(); + + case "exponent2": + return new asn1js.Integer(); + + case "coefficient": + return new asn1js.Integer(); + + case "otherPrimeInfos": + return []; + + default: + throw new Error(`Invalid member name for RSAPrivateKey class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * RSAPrivateKey ::= Sequence { + * version Version, + * modulus Integer, -- n + * publicExponent Integer, -- e + * privateExponent Integer, -- d + * prime1 Integer, -- p + * prime2 Integer, -- q + * exponent1 Integer, -- d mod (p-1) + * exponent2 Integer, -- d mod (q-1) + * coefficient Integer, -- (inverse of q) mod p + * otherPrimeInfos OtherPrimeInfos OPTIONAL + * } + * + * OtherPrimeInfos ::= Sequence SIZE(1..MAX) OF OtherPrimeInfo + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [version] + * @property {string} [modulus] + * @property {string} [publicExponent] + * @property {string} [privateExponent] + * @property {string} [prime1] + * @property {string} [prime2] + * @property {string} [exponent1] + * @property {string} [exponent2] + * @property {string} [coefficient] + * @property {string} [otherPrimeInfosName] + * @property {Object} [otherPrimeInfo] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [new asn1js.Integer({ + name: names.version || "" + }), new asn1js.Integer({ + name: names.modulus || "" + }), new asn1js.Integer({ + name: names.publicExponent || "" + }), new asn1js.Integer({ + name: names.privateExponent || "" + }), new asn1js.Integer({ + name: names.prime1 || "" + }), new asn1js.Integer({ + name: names.prime2 || "" + }), new asn1js.Integer({ + name: names.exponent1 || "" + }), new asn1js.Integer({ + name: names.exponent2 || "" + }), new asn1js.Integer({ + name: names.coefficient || "" + }), new asn1js.Sequence({ + optional: true, + value: [new asn1js.Repeated({ + name: names.otherPrimeInfosName || "", + value: _OtherPrimeInfo.default.schema(names.otherPrimeInfo || {}) + })] + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["version", "modulus", "publicExponent", "privateExponent", "prime1", "prime2", "exponent1", "exponent2", "coefficient", "otherPrimeInfos"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, RSAPrivateKey.schema({ + names: { + version: "version", + modulus: "modulus", + publicExponent: "publicExponent", + privateExponent: "privateExponent", + prime1: "prime1", + prime2: "prime2", + exponent1: "exponent1", + exponent2: "exponent2", + coefficient: "coefficient", + otherPrimeInfo: { + names: { + blockName: "otherPrimeInfos" + } + } + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for RSAPrivateKey"); //endregion + //region Get internal properties from parsed schema + + this.version = asn1.result.version.valueBlock.valueDec; + this.modulus = asn1.result.modulus.convertFromDER(256); + this.publicExponent = asn1.result.publicExponent; + this.privateExponent = asn1.result.privateExponent.convertFromDER(256); + this.prime1 = asn1.result.prime1.convertFromDER(128); + this.prime2 = asn1.result.prime2.convertFromDER(128); + this.exponent1 = asn1.result.exponent1.convertFromDER(128); + this.exponent2 = asn1.result.exponent2.convertFromDER(128); + this.coefficient = asn1.result.coefficient.convertFromDER(128); + if ("otherPrimeInfos" in asn1.result) this.otherPrimeInfos = Array.from(asn1.result.otherPrimeInfos, element => new _OtherPrimeInfo.default({ + schema: element + })); //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Create array for output sequence + const outputArray = []; + outputArray.push(new asn1js.Integer({ + value: this.version + })); + outputArray.push(this.modulus.convertToDER()); + outputArray.push(this.publicExponent); + outputArray.push(this.privateExponent.convertToDER()); + outputArray.push(this.prime1.convertToDER()); + outputArray.push(this.prime2.convertToDER()); + outputArray.push(this.exponent1.convertToDER()); + outputArray.push(this.exponent2.convertToDER()); + outputArray.push(this.coefficient.convertToDER()); + + if ("otherPrimeInfos" in this) { + outputArray.push(new asn1js.Sequence({ + value: Array.from(this.otherPrimeInfos, element => element.toSchema()) + })); + } //endregion + //region Construct and return new ASN.1 schema for this object + + + return new asn1js.Sequence({ + value: outputArray + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + const jwk = { + n: (0, _pvutils.toBase64)((0, _pvutils.arrayBufferToString)(this.modulus.valueBlock.valueHex), true, true, true), + e: (0, _pvutils.toBase64)((0, _pvutils.arrayBufferToString)(this.publicExponent.valueBlock.valueHex), true, true, true), + d: (0, _pvutils.toBase64)((0, _pvutils.arrayBufferToString)(this.privateExponent.valueBlock.valueHex), true, true, true), + p: (0, _pvutils.toBase64)((0, _pvutils.arrayBufferToString)(this.prime1.valueBlock.valueHex), true, true, true), + q: (0, _pvutils.toBase64)((0, _pvutils.arrayBufferToString)(this.prime2.valueBlock.valueHex), true, true, true), + dp: (0, _pvutils.toBase64)((0, _pvutils.arrayBufferToString)(this.exponent1.valueBlock.valueHex), true, true, true), + dq: (0, _pvutils.toBase64)((0, _pvutils.arrayBufferToString)(this.exponent2.valueBlock.valueHex), true, true, true), + qi: (0, _pvutils.toBase64)((0, _pvutils.arrayBufferToString)(this.coefficient.valueBlock.valueHex), true, true, true) + }; + if ("otherPrimeInfos" in this) jwk.oth = Array.from(this.otherPrimeInfos, element => element.toJSON()); + return jwk; + } //********************************************************************************** + + /** + * Convert JSON value into current object + * @param {Object} json + */ + + + fromJSON(json) { + if ("n" in json) this.modulus = new asn1js.Integer({ + valueHex: (0, _pvutils.stringToArrayBuffer)((0, _pvutils.fromBase64)(json.n, true, true)) + });else throw new Error("Absent mandatory parameter \"n\""); + if ("e" in json) this.publicExponent = new asn1js.Integer({ + valueHex: (0, _pvutils.stringToArrayBuffer)((0, _pvutils.fromBase64)(json.e, true, true)) + });else throw new Error("Absent mandatory parameter \"e\""); + if ("d" in json) this.privateExponent = new asn1js.Integer({ + valueHex: (0, _pvutils.stringToArrayBuffer)((0, _pvutils.fromBase64)(json.d, true, true)) + });else throw new Error("Absent mandatory parameter \"d\""); + if ("p" in json) this.prime1 = new asn1js.Integer({ + valueHex: (0, _pvutils.stringToArrayBuffer)((0, _pvutils.fromBase64)(json.p, true, true)) + });else throw new Error("Absent mandatory parameter \"p\""); + if ("q" in json) this.prime2 = new asn1js.Integer({ + valueHex: (0, _pvutils.stringToArrayBuffer)((0, _pvutils.fromBase64)(json.q, true, true)) + });else throw new Error("Absent mandatory parameter \"q\""); + if ("dp" in json) this.exponent1 = new asn1js.Integer({ + valueHex: (0, _pvutils.stringToArrayBuffer)((0, _pvutils.fromBase64)(json.dp, true, true)) + });else throw new Error("Absent mandatory parameter \"dp\""); + if ("dq" in json) this.exponent2 = new asn1js.Integer({ + valueHex: (0, _pvutils.stringToArrayBuffer)((0, _pvutils.fromBase64)(json.dq, true, true)) + });else throw new Error("Absent mandatory parameter \"dq\""); + if ("qi" in json) this.coefficient = new asn1js.Integer({ + valueHex: (0, _pvutils.stringToArrayBuffer)((0, _pvutils.fromBase64)(json.qi, true, true)) + });else throw new Error("Absent mandatory parameter \"qi\""); + if ("oth" in json) this.otherPrimeInfos = Array.from(json.oth, element => new _OtherPrimeInfo.default({ + json: element + })); + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = RSAPrivateKey; + +},{"./OtherPrimeInfo.js":62,"asn1js":112,"pvutils":113}],82:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC3447 + */ +class RSAPublicKey { + //********************************************************************************** + + /** + * Constructor for RSAPublicKey class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + * @property {Integer} [modulus] + * @property {Integer} [publicExponent] + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {Integer} + * @desc Modulus part of RSA public key + */ + this.modulus = (0, _pvutils.getParametersValue)(parameters, "modulus", RSAPublicKey.defaultValues("modulus")); + /** + * @type {Integer} + * @desc Public exponent of RSA public key + */ + + this.publicExponent = (0, _pvutils.getParametersValue)(parameters, "publicExponent", RSAPublicKey.defaultValues("publicExponent")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + //region If input argument array contains "json" for this object + + if ("json" in parameters) this.fromJSON(parameters.json); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "modulus": + return new asn1js.Integer(); + + case "publicExponent": + return new asn1js.Integer(); + + default: + throw new Error(`Invalid member name for RSAPublicKey class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * RSAPublicKey ::= Sequence { + * modulus Integer, -- n + * publicExponent Integer -- e + * } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} utcTimeName Name for "utcTimeName" choice + * @property {string} generalTimeName Name for "generalTimeName" choice + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [new asn1js.Integer({ + name: names.modulus || "" + }), new asn1js.Integer({ + name: names.publicExponent || "" + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["modulus", "publicExponent"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, RSAPublicKey.schema({ + names: { + modulus: "modulus", + publicExponent: "publicExponent" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for RSAPublicKey"); //endregion + //region Get internal properties from parsed schema + + this.modulus = asn1.result.modulus.convertFromDER(256); + this.publicExponent = asn1.result.publicExponent; //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Construct and return new ASN.1 schema for this object + return new asn1js.Sequence({ + value: [this.modulus.convertToDER(), this.publicExponent] + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + return { + n: (0, _pvutils.toBase64)((0, _pvutils.arrayBufferToString)(this.modulus.valueBlock.valueHex), true, true, true), + e: (0, _pvutils.toBase64)((0, _pvutils.arrayBufferToString)(this.publicExponent.valueBlock.valueHex), true, true, true) + }; + } //********************************************************************************** + + /** + * Convert JSON value into current object + * @param {Object} json + */ + + + fromJSON(json) { + if ("n" in json) { + const array = (0, _pvutils.stringToArrayBuffer)((0, _pvutils.fromBase64)(json.n, true)); + this.modulus = new asn1js.Integer({ + valueHex: array.slice(0, Math.pow(2, (0, _pvutils.nearestPowerOf2)(array.byteLength))) + }); + } else throw new Error("Absent mandatory parameter \"n\""); + + if ("e" in json) this.publicExponent = new asn1js.Integer({ + valueHex: (0, _pvutils.stringToArrayBuffer)((0, _pvutils.fromBase64)(json.e, true)).slice(0, 3) + });else throw new Error("Absent mandatory parameter \"e\""); + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = RSAPublicKey; + +},{"asn1js":112,"pvutils":113}],83:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _AlgorithmIdentifier = _interopRequireDefault(require("./AlgorithmIdentifier.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC4055 + */ +class RSASSAPSSParams { + //********************************************************************************** + + /** + * Constructor for RSASSAPSSParams class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {AlgorithmIdentifier} + * @desc Algorithms of hashing (DEFAULT sha1) + */ + this.hashAlgorithm = (0, _pvutils.getParametersValue)(parameters, "hashAlgorithm", RSASSAPSSParams.defaultValues("hashAlgorithm")); + /** + * @type {AlgorithmIdentifier} + * @desc Algorithm of "mask generaion function (MGF)" (DEFAULT mgf1SHA1) + */ + + this.maskGenAlgorithm = (0, _pvutils.getParametersValue)(parameters, "maskGenAlgorithm", RSASSAPSSParams.defaultValues("maskGenAlgorithm")); + /** + * @type {number} + * @desc Salt length (DEFAULT 20) + */ + + this.saltLength = (0, _pvutils.getParametersValue)(parameters, "saltLength", RSASSAPSSParams.defaultValues("saltLength")); + /** + * @type {number} + * @desc (DEFAULT 1) + */ + + this.trailerField = (0, _pvutils.getParametersValue)(parameters, "trailerField", RSASSAPSSParams.defaultValues("trailerField")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "hashAlgorithm": + return new _AlgorithmIdentifier.default({ + algorithmId: "1.3.14.3.2.26", + // SHA-1 + algorithmParams: new asn1js.Null() + }); + + case "maskGenAlgorithm": + return new _AlgorithmIdentifier.default({ + algorithmId: "1.2.840.113549.1.1.8", + // MGF1 + algorithmParams: new _AlgorithmIdentifier.default({ + algorithmId: "1.3.14.3.2.26", + // SHA-1 + algorithmParams: new asn1js.Null() + }).toSchema() + }); + + case "saltLength": + return 20; + + case "trailerField": + return 1; + + default: + throw new Error(`Invalid member name for RSASSAPSSParams class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * RSASSA-PSS-params ::= Sequence { + * hashAlgorithm [0] HashAlgorithm DEFAULT sha1Identifier, + * maskGenAlgorithm [1] MaskGenAlgorithm DEFAULT mgf1SHA1Identifier, + * saltLength [2] Integer DEFAULT 20, + * trailerField [3] Integer DEFAULT 1 } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [hashAlgorithm] + * @property {string} [maskGenAlgorithm] + * @property {string} [saltLength] + * @property {string} [trailerField] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [new asn1js.Constructed({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + optional: true, + value: [_AlgorithmIdentifier.default.schema(names.hashAlgorithm || {})] + }), new asn1js.Constructed({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + + }, + optional: true, + value: [_AlgorithmIdentifier.default.schema(names.maskGenAlgorithm || {})] + }), new asn1js.Constructed({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 2 // [2] + + }, + optional: true, + value: [new asn1js.Integer({ + name: names.saltLength || "" + })] + }), new asn1js.Constructed({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 3 // [3] + + }, + optional: true, + value: [new asn1js.Integer({ + name: names.trailerField || "" + })] + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["hashAlgorithm", "maskGenAlgorithm", "saltLength", "trailerField"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, RSASSAPSSParams.schema({ + names: { + hashAlgorithm: { + names: { + blockName: "hashAlgorithm" + } + }, + maskGenAlgorithm: { + names: { + blockName: "maskGenAlgorithm" + } + }, + saltLength: "saltLength", + trailerField: "trailerField" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for RSASSAPSSParams"); //endregion + //region Get internal properties from parsed schema + + if ("hashAlgorithm" in asn1.result) this.hashAlgorithm = new _AlgorithmIdentifier.default({ + schema: asn1.result.hashAlgorithm + }); + if ("maskGenAlgorithm" in asn1.result) this.maskGenAlgorithm = new _AlgorithmIdentifier.default({ + schema: asn1.result.maskGenAlgorithm + }); + if ("saltLength" in asn1.result) this.saltLength = asn1.result.saltLength.valueBlock.valueDec; + if ("trailerField" in asn1.result) this.trailerField = asn1.result.trailerField.valueBlock.valueDec; //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Create array for output sequence + const outputArray = []; + + if (!this.hashAlgorithm.isEqual(RSASSAPSSParams.defaultValues("hashAlgorithm"))) { + outputArray.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: [this.hashAlgorithm.toSchema()] + })); + } + + if (!this.maskGenAlgorithm.isEqual(RSASSAPSSParams.defaultValues("maskGenAlgorithm"))) { + outputArray.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + + }, + value: [this.maskGenAlgorithm.toSchema()] + })); + } + + if (this.saltLength !== RSASSAPSSParams.defaultValues("saltLength")) { + outputArray.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 2 // [2] + + }, + value: [new asn1js.Integer({ + value: this.saltLength + })] + })); + } + + if (this.trailerField !== RSASSAPSSParams.defaultValues("trailerField")) { + outputArray.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 3 // [3] + + }, + value: [new asn1js.Integer({ + value: this.trailerField + })] + })); + } //endregion + //region Construct and return new ASN.1 schema for this object + + + return new asn1js.Sequence({ + value: outputArray + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + const object = {}; + if (!this.hashAlgorithm.isEqual(RSASSAPSSParams.defaultValues("hashAlgorithm"))) object.hashAlgorithm = this.hashAlgorithm.toJSON(); + if (!this.maskGenAlgorithm.isEqual(RSASSAPSSParams.defaultValues("maskGenAlgorithm"))) object.maskGenAlgorithm = this.maskGenAlgorithm.toJSON(); + if (this.saltLength !== RSASSAPSSParams.defaultValues("saltLength")) object.saltLength = this.saltLength; + if (this.trailerField !== RSASSAPSSParams.defaultValues("trailerField")) object.trailerField = this.trailerField; + return object; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = RSASSAPSSParams; + +},{"./AlgorithmIdentifier.js":4,"asn1js":112,"pvutils":113}],84:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _KeyAgreeRecipientIdentifier = _interopRequireDefault(require("./KeyAgreeRecipientIdentifier.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC5652 + */ +class RecipientEncryptedKey { + //********************************************************************************** + + /** + * Constructor for RecipientEncryptedKey class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {KeyAgreeRecipientIdentifier} + * @desc rid + */ + this.rid = (0, _pvutils.getParametersValue)(parameters, "rid", RecipientEncryptedKey.defaultValues("rid")); + /** + * @type {OctetString} + * @desc encryptedKey + */ + + this.encryptedKey = (0, _pvutils.getParametersValue)(parameters, "encryptedKey", RecipientEncryptedKey.defaultValues("encryptedKey")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "rid": + return new _KeyAgreeRecipientIdentifier.default(); + + case "encryptedKey": + return new asn1js.OctetString(); + + default: + throw new Error(`Invalid member name for RecipientEncryptedKey class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + + + static compareWithDefault(memberName, memberValue) { + switch (memberName) { + case "rid": + return memberValue.variant === -1 && "value" in memberValue === false; + + case "encryptedKey": + return memberValue.isEqual(RecipientEncryptedKey.defaultValues("encryptedKey")); + + default: + throw new Error(`Invalid member name for RecipientEncryptedKey class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * RecipientEncryptedKey ::= SEQUENCE { + * rid KeyAgreeRecipientIdentifier, + * encryptedKey EncryptedKey } + * + * EncryptedKey ::= OCTET STRING + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [rid] + * @property {string} [encryptedKey] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [_KeyAgreeRecipientIdentifier.default.schema(names.rid || {}), new asn1js.OctetString({ + name: names.encryptedKey || "" + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["rid", "encryptedKey"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, RecipientEncryptedKey.schema({ + names: { + rid: { + names: { + blockName: "rid" + } + }, + encryptedKey: "encryptedKey" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for RecipientEncryptedKey"); //endregion + //region Get internal properties from parsed schema + + this.rid = new _KeyAgreeRecipientIdentifier.default({ + schema: asn1.result.rid + }); + this.encryptedKey = asn1.result.encryptedKey; //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Construct and return new ASN.1 schema for this object + return new asn1js.Sequence({ + value: [this.rid.toSchema(), this.encryptedKey] + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + return { + rid: this.rid.toJSON(), + encryptedKey: this.encryptedKey.toJSON() + }; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = RecipientEncryptedKey; + +},{"./KeyAgreeRecipientIdentifier.js":48,"asn1js":112,"pvutils":113}],85:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _RecipientEncryptedKey = _interopRequireDefault(require("./RecipientEncryptedKey.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC5652 + */ +class RecipientEncryptedKeys { + //********************************************************************************** + + /** + * Constructor for RecipientEncryptedKeys class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {Array.} + * @desc encryptedKeys + */ + this.encryptedKeys = (0, _pvutils.getParametersValue)(parameters, "encryptedKeys", RecipientEncryptedKeys.defaultValues("encryptedKeys")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "encryptedKeys": + return []; + + default: + throw new Error(`Invalid member name for RecipientEncryptedKeys class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + + + static compareWithDefault(memberName, memberValue) { + switch (memberName) { + case "encryptedKeys": + return memberValue.length === 0; + + default: + throw new Error(`Invalid member name for RecipientEncryptedKeys class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * RecipientEncryptedKeys ::= SEQUENCE OF RecipientEncryptedKey + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [RecipientEncryptedKeys] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [new asn1js.Repeated({ + name: names.RecipientEncryptedKeys || "", + value: _RecipientEncryptedKey.default.schema() + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["RecipientEncryptedKeys"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, RecipientEncryptedKeys.schema({ + names: { + RecipientEncryptedKeys: "RecipientEncryptedKeys" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for RecipientEncryptedKeys"); //endregion + //region Get internal properties from parsed schema + + this.encryptedKeys = Array.from(asn1.result.RecipientEncryptedKeys, element => new _RecipientEncryptedKey.default({ + schema: element + })); //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Construct and return new ASN.1 schema for this object + return new asn1js.Sequence({ + value: Array.from(this.encryptedKeys, element => element.toSchema()) + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + return { + encryptedKeys: Array.from(this.encryptedKeys, element => element.toJSON()) + }; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = RecipientEncryptedKeys; + +},{"./RecipientEncryptedKey.js":84,"asn1js":112,"pvutils":113}],86:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _IssuerAndSerialNumber = _interopRequireDefault(require("./IssuerAndSerialNumber.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC5652 + */ +class RecipientIdentifier { + //********************************************************************************** + + /** + * Constructor for RecipientIdentifier class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {number} + * @desc variant + */ + this.variant = (0, _pvutils.getParametersValue)(parameters, "variant", RecipientIdentifier.defaultValues("variant")); + if ("value" in parameters) + /** + * @type {*} + * @desc value + */ + this.value = (0, _pvutils.getParametersValue)(parameters, "value", RecipientIdentifier.defaultValues("value")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "variant": + return -1; + + case "value": + return {}; + + default: + throw new Error(`Invalid member name for RecipientIdentifier class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + + + static compareWithDefault(memberName, memberValue) { + switch (memberName) { + case "variant": + return memberValue === -1; + + case "values": + return Object.keys(memberValue).length === 0; + + default: + throw new Error(`Invalid member name for RecipientIdentifier class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * RecipientIdentifier ::= CHOICE { + * issuerAndSerialNumber IssuerAndSerialNumber, + * subjectKeyIdentifier [0] SubjectKeyIdentifier } + * + * SubjectKeyIdentifier ::= OCTET STRING + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Choice({ + value: [_IssuerAndSerialNumber.default.schema({ + names: { + blockName: names.blockName || "" + } + }), new asn1js.Constructed({ + name: names.blockName || "", + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: [new asn1js.OctetString()] + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["blockName"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, RecipientIdentifier.schema({ + names: { + blockName: "blockName" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for RecipientIdentifier"); //endregion + //region Get internal properties from parsed schema + + if (asn1.result.blockName.idBlock.tagClass === 1) { + this.variant = 1; + this.value = new _IssuerAndSerialNumber.default({ + schema: asn1.result.blockName + }); + } else { + this.variant = 2; + this.value = asn1.result.blockName.valueBlock.value[0]; + } //endregion + + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Construct and return new ASN.1 schema for this object + switch (this.variant) { + case 1: + return this.value.toSchema(); + + case 2: + return new asn1js.Constructed({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: [this.value] + }); + + default: + return new asn1js.Any(); + } //endregion + + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + const _object = { + variant: this.variant + }; + if (this.variant === 1 || this.variant === 2) _object.value = this.value.toJSON(); + return _object; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = RecipientIdentifier; + +},{"./IssuerAndSerialNumber.js":44,"asn1js":112,"pvutils":113}],87:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _KeyTransRecipientInfo = _interopRequireDefault(require("./KeyTransRecipientInfo.js")); + +var _KeyAgreeRecipientInfo = _interopRequireDefault(require("./KeyAgreeRecipientInfo.js")); + +var _KEKRecipientInfo = _interopRequireDefault(require("./KEKRecipientInfo.js")); + +var _PasswordRecipientinfo = _interopRequireDefault(require("./PasswordRecipientinfo.js")); + +var _OtherRecipientInfo = _interopRequireDefault(require("./OtherRecipientInfo.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC5652 + */ +class RecipientInfo { + //********************************************************************************** + + /** + * Constructor for RecipientInfo class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {string} + * @desc variant + */ + this.variant = (0, _pvutils.getParametersValue)(parameters, "variant", RecipientInfo.defaultValues("variant")); + if ("value" in parameters) + /** + * @type {*} + * @desc value + */ + this.value = (0, _pvutils.getParametersValue)(parameters, "value", RecipientInfo.defaultValues("value")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "variant": + return -1; + + case "value": + return {}; + + default: + throw new Error(`Invalid member name for RecipientInfo class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + + + static compareWithDefault(memberName, memberValue) { + switch (memberName) { + case "variant": + return memberValue === RecipientInfo.defaultValues(memberName); + + case "value": + return Object.keys(memberValue).length === 0; + + default: + throw new Error(`Invalid member name for RecipientInfo class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * RecipientInfo ::= CHOICE { + * ktri KeyTransRecipientInfo, + * kari [1] KeyAgreeRecipientInfo, + * kekri [2] KEKRecipientInfo, + * pwri [3] PasswordRecipientinfo, + * ori [4] OtherRecipientInfo } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [type] + * @property {string} [setName] + * @property {string} [values] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Choice({ + value: [_KeyTransRecipientInfo.default.schema({ + names: { + blockName: names.blockName || "" + } + }), new asn1js.Constructed({ + name: names.blockName || "", + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + + }, + value: _KeyAgreeRecipientInfo.default.schema().valueBlock.value + }), new asn1js.Constructed({ + name: names.blockName || "", + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 2 // [2] + + }, + value: _KEKRecipientInfo.default.schema().valueBlock.value + }), new asn1js.Constructed({ + name: names.blockName || "", + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 3 // [3] + + }, + value: _PasswordRecipientinfo.default.schema().valueBlock.value + }), new asn1js.Constructed({ + name: names.blockName || "", + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 4 // [4] + + }, + value: _OtherRecipientInfo.default.schema().valueBlock.value + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["blockName"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, RecipientInfo.schema({ + names: { + blockName: "blockName" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for RecipientInfo"); //endregion + //region Get internal properties from parsed schema + + if (asn1.result.blockName.idBlock.tagClass === 1) { + this.variant = 1; + this.value = new _KeyTransRecipientInfo.default({ + schema: asn1.result.blockName + }); + } else { + //region Create "SEQUENCE" from "ASN1_CONSTRUCTED" + const blockSequence = new asn1js.Sequence({ + value: asn1.result.blockName.valueBlock.value + }); //endregion + + switch (asn1.result.blockName.idBlock.tagNumber) { + case 1: + this.variant = 2; + this.value = new _KeyAgreeRecipientInfo.default({ + schema: blockSequence + }); + break; + + case 2: + this.variant = 3; + this.value = new _KEKRecipientInfo.default({ + schema: blockSequence + }); + break; + + case 3: + this.variant = 4; + this.value = new _PasswordRecipientinfo.default({ + schema: blockSequence + }); + break; + + case 4: + this.variant = 5; + this.value = new _OtherRecipientInfo.default({ + schema: blockSequence + }); + break; + + default: + throw new Error("Incorrect structure of RecipientInfo block"); + } + } //endregion + + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Construct and return new ASN.1 schema for this object + const _schema = this.value.toSchema(); + + switch (this.variant) { + case 1: + return _schema; + + case 2: + case 3: + case 4: + //region Create "ASN1_CONSTRUCTED" from "SEQUENCE" + _schema.idBlock.tagClass = 3; // CONTEXT-SPECIFIC + + _schema.idBlock.tagNumber = this.variant - 1; //endregion + + return _schema; + + default: + return new asn1js.Any(); + } //endregion + + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + const _object = { + variant: this.variant + }; + if (this.variant >= 1 && this.variant <= 4) _object.value = this.value.toJSON(); + return _object; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = RecipientInfo; + +},{"./KEKRecipientInfo.js":47,"./KeyAgreeRecipientInfo.js":49,"./KeyTransRecipientInfo.js":51,"./OtherRecipientInfo.js":63,"./PasswordRecipientinfo.js":70,"asn1js":112,"pvutils":113}],88:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _OtherKeyAttribute = _interopRequireDefault(require("./OtherKeyAttribute.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC5652 + */ +class RecipientKeyIdentifier { + //********************************************************************************** + + /** + * Constructor for RecipientKeyIdentifier class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {OctetString} + * @desc subjectKeyIdentifier + */ + this.subjectKeyIdentifier = (0, _pvutils.getParametersValue)(parameters, "subjectKeyIdentifier", RecipientKeyIdentifier.defaultValues("subjectKeyIdentifier")); + if ("date" in parameters) + /** + * @type {GeneralizedTime} + * @desc date + */ + this.date = (0, _pvutils.getParametersValue)(parameters, "date", RecipientKeyIdentifier.defaultValues("date")); + if ("other" in parameters) + /** + * @type {OtherKeyAttribute} + * @desc other + */ + this.other = (0, _pvutils.getParametersValue)(parameters, "other", RecipientKeyIdentifier.defaultValues("other")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "subjectKeyIdentifier": + return new asn1js.OctetString(); + + case "date": + return new asn1js.GeneralizedTime(); + + case "other": + return new _OtherKeyAttribute.default(); + + default: + throw new Error(`Invalid member name for RecipientKeyIdentifier class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + + + static compareWithDefault(memberName, memberValue) { + switch (memberName) { + case "subjectKeyIdentifier": + return memberValue.isEqual(RecipientKeyIdentifier.defaultValues("subjectKeyIdentifier")); + + case "date": + // noinspection OverlyComplexBooleanExpressionJS + return memberValue.year === 0 && memberValue.month === 0 && memberValue.day === 0 && memberValue.hour === 0 && memberValue.minute === 0 && memberValue.second === 0 && memberValue.millisecond === 0; + + case "other": + return memberValue.keyAttrId === "" && "keyAttr" in memberValue === false; + + default: + throw new Error(`Invalid member name for RecipientKeyIdentifier class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * RecipientKeyIdentifier ::= SEQUENCE { + * subjectKeyIdentifier SubjectKeyIdentifier, + * date GeneralizedTime OPTIONAL, + * other OtherKeyAttribute OPTIONAL } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [type] + * @property {string} [setName] + * @property {string} [values] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [new asn1js.OctetString({ + name: names.subjectKeyIdentifier || "" + }), new asn1js.GeneralizedTime({ + optional: true, + name: names.date || "" + }), _OtherKeyAttribute.default.schema(names.other || {})] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["subjectKeyIdentifier", "date", "other"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, RecipientKeyIdentifier.schema({ + names: { + subjectKeyIdentifier: "subjectKeyIdentifier", + date: "date", + other: { + names: { + blockName: "other" + } + } + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for RecipientKeyIdentifier"); //endregion + //region Get internal properties from parsed schema + + this.subjectKeyIdentifier = asn1.result.subjectKeyIdentifier; + if ("date" in asn1.result) this.date = asn1.result.date; + if ("other" in asn1.result) this.other = new _OtherKeyAttribute.default({ + schema: asn1.result.other + }); //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Create array for output sequence + const outputArray = []; + outputArray.push(this.subjectKeyIdentifier); + if ("date" in this) outputArray.push(this.date); + if ("other" in this) outputArray.push(this.other.toSchema()); //endregion + //region Construct and return new ASN.1 schema for this object + + return new asn1js.Sequence({ + value: outputArray + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + const _object = { + subjectKeyIdentifier: this.subjectKeyIdentifier.toJSON() + }; + if ("date" in this) _object.date = this.date; + if ("other" in this) _object.other = this.other.toJSON(); + return _object; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = RecipientKeyIdentifier; + +},{"./OtherKeyAttribute.js":61,"asn1js":112,"pvutils":113}],89:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _AttributeTypeAndValue = _interopRequireDefault(require("./AttributeTypeAndValue.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); } + +function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } + +function _iterableToArrayLimit(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } + +function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } + +//************************************************************************************** + +/** + * Class from RFC5280 + */ +class RelativeDistinguishedNames { + //********************************************************************************** + + /** + * Constructor for RelativeDistinguishedNames class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + * @property {Array.} [typesAndValues] Array of "type and value" objects + * @property {ArrayBuffer} [valueBeforeDecode] Value of the RDN before decoding from schema + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {Array.} + * @desc Array of "type and value" objects + */ + this.typesAndValues = (0, _pvutils.getParametersValue)(parameters, "typesAndValues", RelativeDistinguishedNames.defaultValues("typesAndValues")); + /** + * @type {ArrayBuffer} + * @desc Value of the RDN before decoding from schema + */ + + this.valueBeforeDecode = (0, _pvutils.getParametersValue)(parameters, "valueBeforeDecode", RelativeDistinguishedNames.defaultValues("valueBeforeDecode")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "typesAndValues": + return []; + + case "valueBeforeDecode": + return new ArrayBuffer(0); + + default: + throw new Error(`Invalid member name for RelativeDistinguishedNames class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + + + static compareWithDefault(memberName, memberValue) { + switch (memberName) { + case "typesAndValues": + return memberValue.length === 0; + + case "valueBeforeDecode": + return memberValue.byteLength === 0; + + default: + throw new Error(`Invalid member name for RelativeDistinguishedNames class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * RDNSequence ::= Sequence OF RelativeDistinguishedName + * + * RelativeDistinguishedName ::= + * SET SIZE (1..MAX) OF AttributeTypeAndValue + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] Name for entire block + * @property {string} [repeatedSequence] Name for "repeatedSequence" block + * @property {string} [repeatedSet] Name for "repeatedSet" block + * @property {string} [typeAndValue] Name for "typeAndValue" block + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [new asn1js.Repeated({ + name: names.repeatedSequence || "", + value: new asn1js.Set({ + value: [new asn1js.Repeated({ + name: names.repeatedSet || "", + value: _AttributeTypeAndValue.default.schema(names.typeAndValue || {}) + })] + }) + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["RDN", "typesAndValues"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, RelativeDistinguishedNames.schema({ + names: { + blockName: "RDN", + repeatedSet: "typesAndValues" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for RelativeDistinguishedNames"); //endregion + //region Get internal properties from parsed schema + + if ("typesAndValues" in asn1.result) // Could be a case when there is no "types and values" + this.typesAndValues = Array.from(asn1.result.typesAndValues, element => new _AttributeTypeAndValue.default({ + schema: element + })); // noinspection JSUnresolvedVariable + + this.valueBeforeDecode = asn1.result.RDN.valueBeforeDecode; //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Decode stored TBS value + if (this.valueBeforeDecode.byteLength === 0) // No stored encoded array, create "from scratch" + { + return new asn1js.Sequence({ + value: [new asn1js.Set({ + value: Array.from(this.typesAndValues, element => element.toSchema()) + })] + }); + } + + const asn1 = asn1js.fromBER(this.valueBeforeDecode); //endregion + //region Construct and return new ASN.1 schema for this object + + return asn1.result; //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + return { + typesAndValues: Array.from(this.typesAndValues, element => element.toJSON()) + }; + } //********************************************************************************** + + /** + * Compare two RDN values, or RDN with ArrayBuffer value + * @param {(RelativeDistinguishedNames|ArrayBuffer)} compareTo The value compare to current + * @returns {boolean} + */ + + + isEqual(compareTo) { + if (compareTo instanceof RelativeDistinguishedNames) { + if (this.typesAndValues.length !== compareTo.typesAndValues.length) return false; + var _iteratorNormalCompletion = true; + var _didIteratorError = false; + var _iteratorError = undefined; + + try { + for (var _iterator = this.typesAndValues.entries()[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { + const _step$value = _slicedToArray(_step.value, 2), + index = _step$value[0], + typeAndValue = _step$value[1]; + + if (typeAndValue.isEqual(compareTo.typesAndValues[index]) === false) return false; + } + } catch (err) { + _didIteratorError = true; + _iteratorError = err; + } finally { + try { + if (!_iteratorNormalCompletion && _iterator.return != null) { + _iterator.return(); + } + } finally { + if (_didIteratorError) { + throw _iteratorError; + } + } + } + + return true; + } + + if (compareTo instanceof ArrayBuffer) return (0, _pvutils.isEqualBuffer)(this.valueBeforeDecode, compareTo); + return false; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = RelativeDistinguishedNames; + +},{"./AttributeTypeAndValue.js":9,"asn1js":112,"pvutils":113}],90:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _CertID = _interopRequireDefault(require("./CertID.js")); + +var _Extension = _interopRequireDefault(require("./Extension.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC6960 + */ +class Request { + //********************************************************************************** + + /** + * Constructor for Request class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {CertID} + * @desc reqCert + */ + this.reqCert = (0, _pvutils.getParametersValue)(parameters, "reqCert", Request.defaultValues("reqCert")); + if ("singleRequestExtensions" in parameters) + /** + * @type {Array.} + * @desc singleRequestExtensions + */ + this.singleRequestExtensions = (0, _pvutils.getParametersValue)(parameters, "singleRequestExtensions", Request.defaultValues("singleRequestExtensions")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "reqCert": + return new _CertID.default(); + + case "singleRequestExtensions": + return []; + + default: + throw new Error(`Invalid member name for Request class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + + + static compareWithDefault(memberName, memberValue) { + switch (memberName) { + case "reqCert": + return memberValue.isEqual(Request.defaultValues(memberName)); + + case "singleRequestExtensions": + return memberValue.length === 0; + + default: + throw new Error(`Invalid member name for Request class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * Request ::= SEQUENCE { + * reqCert CertID, + * singleRequestExtensions [0] EXPLICIT Extensions OPTIONAL } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [reqCert] + * @property {string} [extensions] + * @property {string} [singleRequestExtensions] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [_CertID.default.schema(names.reqCert || {}), new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: [_Extension.default.schema(names.extensions || { + names: { + blockName: names.singleRequestExtensions || "" + } + })] + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["reqCert", "singleRequestExtensions"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, Request.schema({ + names: { + reqCert: { + names: { + blockName: "reqCert" + } + }, + singleRequestExtensions: { + names: { + blockName: "singleRequestExtensions" + } + } + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for Request"); //endregion + //region Get internal properties from parsed schema + + this.reqCert = new _CertID.default({ + schema: asn1.result.reqCert + }); + if ("singleRequestExtensions" in asn1.result) this.singleRequestExtensions = Array.from(asn1.result.singleRequestExtensions.valueBlock.value, element => new _Extension.default({ + schema: element + })); //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Create array for output sequence + const outputArray = []; + outputArray.push(this.reqCert.toSchema()); + + if ("singleRequestExtensions" in this) { + outputArray.push(new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: [new asn1js.Sequence({ + value: Array.from(this.singleRequestExtensions, element => element.toSchema()) + })] + })); + } //endregion + //region Construct and return new ASN.1 schema for this object + + + return new asn1js.Sequence({ + value: outputArray + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + const _object = { + reqCert: this.reqCert.toJSON() + }; + if ("singleRequestExtensions" in this) _object.singleRequestExtensions = Array.from(this.singleRequestExtensions, element => element.toJSON()); + return _object; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = Request; + +},{"./CertID.js":18,"./Extension.js":38,"asn1js":112,"pvutils":113}],91:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC6960 + */ +class ResponseBytes { + //********************************************************************************** + + /** + * Constructor for ResponseBytes class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {string} + * @desc responseType + */ + this.responseType = (0, _pvutils.getParametersValue)(parameters, "responseType", ResponseBytes.defaultValues("responseType")); + /** + * @type {OctetString} + * @desc response + */ + + this.response = (0, _pvutils.getParametersValue)(parameters, "response", ResponseBytes.defaultValues("response")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "responseType": + return ""; + + case "response": + return new asn1js.OctetString(); + + default: + throw new Error(`Invalid member name for ResponseBytes class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + + + static compareWithDefault(memberName, memberValue) { + switch (memberName) { + case "responseType": + return memberValue === ""; + + case "response": + return memberValue.isEqual(ResponseBytes.defaultValues(memberName)); + + default: + throw new Error(`Invalid member name for ResponseBytes class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * ResponseBytes ::= SEQUENCE { + * responseType OBJECT IDENTIFIER, + * response OCTET STRING } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [responseType] + * @property {string} [response] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [new asn1js.ObjectIdentifier({ + name: names.responseType || "" + }), new asn1js.OctetString({ + name: names.response || "" + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["responseType", "response"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, ResponseBytes.schema({ + names: { + responseType: "responseType", + response: "response" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for ResponseBytes"); //endregion + //region Get internal properties from parsed schema + + this.responseType = asn1.result.responseType.valueBlock.toString(); + this.response = asn1.result.response; //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Construct and return new ASN.1 schema for this object + return new asn1js.Sequence({ + value: [new asn1js.ObjectIdentifier({ + value: this.responseType + }), this.response] + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + return { + responseType: this.responseType, + response: this.response.toJSON() + }; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = ResponseBytes; + +},{"asn1js":112,"pvutils":113}],92:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _RelativeDistinguishedNames = _interopRequireDefault(require("./RelativeDistinguishedNames.js")); + +var _SingleResponse = _interopRequireDefault(require("./SingleResponse.js")); + +var _Extension = _interopRequireDefault(require("./Extension.js")); + +var _Extensions = _interopRequireDefault(require("./Extensions.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC6960 + */ +class ResponseData { + //********************************************************************************** + + /** + * Constructor for ResponseData class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {ArrayBuffer} + * @desc tbs + */ + this.tbs = (0, _pvutils.getParametersValue)(parameters, "tbs", ResponseData.defaultValues("tbs")); + /** + * @type {Object} + * @desc responderID + */ + + this.responderID = (0, _pvutils.getParametersValue)(parameters, "responderID", ResponseData.defaultValues("responderID")); + /** + * @type {Date} + * @desc producedAt + */ + + this.producedAt = (0, _pvutils.getParametersValue)(parameters, "producedAt", ResponseData.defaultValues("producedAt")); + /** + * @type {Array.} + * @desc responses + */ + + this.responses = (0, _pvutils.getParametersValue)(parameters, "responses", ResponseData.defaultValues("responses")); + if ("responseExtensions" in parameters) + /** + * @type {Array.} + * @desc responseExtensions + */ + this.responseExtensions = (0, _pvutils.getParametersValue)(parameters, "responseExtensions", ResponseData.defaultValues("responseExtensions")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "tbs": + return new ArrayBuffer(0); + + case "responderID": + return {}; + + case "producedAt": + return new Date(0, 0, 0); + + case "responses": + case "responseExtensions": + return []; + + default: + throw new Error(`Invalid member name for ResponseData class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + + + static compareWithDefault(memberName, memberValue) { + switch (memberName) { + case "tbs": + return memberValue.byteLength === 0; + + case "responderID": + return Object.keys(memberValue).length === 0; + + case "producedAt": + return memberValue === ResponseData.defaultValues(memberName); + + case "responses": + case "responseExtensions": + return memberValue.length === 0; + + default: + throw new Error(`Invalid member name for ResponseData class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * ResponseData ::= SEQUENCE { + * version [0] EXPLICIT Version DEFAULT v1, + * responderID ResponderID, + * producedAt GeneralizedTime, + * responses SEQUENCE OF SingleResponse, + * responseExtensions [1] EXPLICIT Extensions OPTIONAL } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [version] + * @property {string} [ResponseDataByName] + * @property {string} [ResponseDataByKey] + * @property {string} [producedAt] + * @property {string} [response] + * @property {string} [extensions] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "ResponseData", + value: [new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: [new asn1js.Integer({ + name: names.version || "ResponseData.version" + })] + }), new asn1js.Choice({ + value: [new asn1js.Constructed({ + name: names.responderID || "ResponseData.responderID", + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + + }, + value: [_RelativeDistinguishedNames.default.schema(names.ResponseDataByName || { + names: { + blockName: "ResponseData.byName" + } + })] + }), new asn1js.Constructed({ + name: names.responderID || "ResponseData.responderID", + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 2 // [2] + + }, + value: [new asn1js.OctetString({ + name: names.ResponseDataByKey || "ResponseData.byKey" + })] + })] + }), new asn1js.GeneralizedTime({ + name: names.producedAt || "ResponseData.producedAt" + }), new asn1js.Sequence({ + value: [new asn1js.Repeated({ + name: "ResponseData.responses", + value: _SingleResponse.default.schema(names.response || {}) + })] + }), new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + + }, + value: [_Extensions.default.schema(names.extensions || { + names: { + blockName: "ResponseData.responseExtensions" + } + })] + }) // EXPLICIT SEQUENCE value + ] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["ResponseData", "ResponseData.version", "ResponseData.responderID", "ResponseData.producedAt", "ResponseData.responses", "ResponseData.responseExtensions"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, ResponseData.schema()); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for ResponseData"); //endregion + //region Get internal properties from parsed schema + + this.tbs = asn1.result.ResponseData.valueBeforeDecode; + if ("ResponseData.version" in asn1.result) this.version = asn1.result["ResponseData.version"].valueBlock.valueDec; + if (asn1.result["ResponseData.responderID"].idBlock.tagNumber === 1) this.responderID = new _RelativeDistinguishedNames.default({ + schema: asn1.result["ResponseData.responderID"].valueBlock.value[0] + });else this.responderID = asn1.result["ResponseData.responderID"].valueBlock.value[0]; // OCTETSTRING + + this.producedAt = asn1.result["ResponseData.producedAt"].toDate(); + this.responses = Array.from(asn1.result["ResponseData.responses"], element => new _SingleResponse.default({ + schema: element + })); + if ("ResponseData.responseExtensions" in asn1.result) this.responseExtensions = Array.from(asn1.result["ResponseData.responseExtensions"].valueBlock.value, element => new _Extension.default({ + schema: element + })); //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @param {boolean} encodeFlag If param equal to false then create TBS schema via decoding stored value. In othe case create TBS schema via assembling from TBS parts. + * @returns {Object} asn1js object + */ + + + toSchema(encodeFlag = false) { + //region Decode stored TBS value + let tbsSchema; + + if (encodeFlag === false) { + if (this.tbs.length === 0) // No stored certificate TBS part + return ResponseData.schema(); + tbsSchema = asn1js.fromBER(this.tbs).result; + } //endregion + //region Create TBS schema via assembling from TBS parts + else { + const outputArray = []; + + if ("version" in this) { + outputArray.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: [new asn1js.Integer({ + value: this.version + })] + })); + } + + if (this.responderID instanceof _RelativeDistinguishedNames.default) { + outputArray.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + + }, + value: [this.responderID.toSchema()] + })); + } else { + outputArray.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 2 // [2] + + }, + value: [this.responderID] + })); + } + + outputArray.push(new asn1js.GeneralizedTime({ + valueDate: this.producedAt + })); + outputArray.push(new asn1js.Sequence({ + value: Array.from(this.responses, element => element.toSchema()) + })); + + if ("responseExtensions" in this) { + outputArray.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + + }, + value: [new asn1js.Sequence({ + value: Array.from(this.responseExtensions, element => element.toSchema()) + })] + })); + } + + tbsSchema = new asn1js.Sequence({ + value: outputArray + }); + } //endregion + //region Construct and return new ASN.1 schema for this object + + + return tbsSchema; //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + const _object = {}; + if ("version" in this) _object.version = this.version; + if ("responderID" in this) _object.responderID = this.responderID; + if ("producedAt" in this) _object.producedAt = this.producedAt; + if ("responses" in this) _object.responses = Array.from(this.responses, element => element.toJSON()); + if ("responseExtensions" in this) _object.responseExtensions = Array.from(this.responseExtensions, element => element.toJSON()); + return _object; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = ResponseData; + +},{"./Extension.js":38,"./Extensions.js":39,"./RelativeDistinguishedNames.js":89,"./SingleResponse.js":103,"asn1js":112,"pvutils":113}],93:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _CertificateRevocationList = _interopRequireDefault(require("./CertificateRevocationList.js")); + +var _OtherRevocationInfoFormat = _interopRequireDefault(require("./OtherRevocationInfoFormat.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC5652 + */ +class RevocationInfoChoices { + //********************************************************************************** + + /** + * Constructor for RevocationInfoChoices class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {Array.} + * @desc crls + */ + this.crls = (0, _pvutils.getParametersValue)(parameters, "crls", RevocationInfoChoices.defaultValues("crls")); + /** + * @type {Array.} + * @desc otherRevocationInfos + */ + + this.otherRevocationInfos = (0, _pvutils.getParametersValue)(parameters, "otherRevocationInfos", RevocationInfoChoices.defaultValues("otherRevocationInfos")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "crls": + return []; + + case "otherRevocationInfos": + return []; + + default: + throw new Error(`Invalid member name for RevocationInfoChoices class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * RevocationInfoChoices ::= SET OF RevocationInfoChoice + * + * RevocationInfoChoice ::= CHOICE { + * crl CertificateList, + * other [1] IMPLICIT OtherRevocationInfoFormat } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [crls] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Set({ + name: names.blockName || "", + value: [new asn1js.Repeated({ + name: names.crls || "", + value: new asn1js.Choice({ + value: [_CertificateRevocationList.default.schema(), new asn1js.Constructed({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + + }, + value: [new asn1js.ObjectIdentifier(), new asn1js.Any()] + })] + }) + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["crls"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, RevocationInfoChoices.schema({ + names: { + crls: "crls" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for RevocationInfoChoices"); //endregion + //region Get internal properties from parsed schema + + var _iteratorNormalCompletion = true; + var _didIteratorError = false; + var _iteratorError = undefined; + + try { + for (var _iterator = asn1.result.crls[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { + const element = _step.value; + if (element.idBlock.tagClass === 1) this.crls.push(new _CertificateRevocationList.default({ + schema: element + }));else this.otherRevocationInfos.push(new _OtherRevocationInfoFormat.default({ + schema: element + })); + } //endregion + + } catch (err) { + _didIteratorError = true; + _iteratorError = err; + } finally { + try { + if (!_iteratorNormalCompletion && _iterator.return != null) { + _iterator.return(); + } + } finally { + if (_didIteratorError) { + throw _iteratorError; + } + } + } + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Create array for output set + const outputArray = []; + outputArray.push(...Array.from(this.crls, element => element.toSchema())); + outputArray.push(...Array.from(this.otherRevocationInfos, element => { + const schema = element.toSchema(); + schema.idBlock.tagClass = 3; + schema.idBlock.tagNumber = 1; + return schema; + })); //endregion + //region Construct and return new ASN.1 schema for this object + + return new asn1js.Set({ + value: outputArray + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + return { + crls: Array.from(this.crls, element => element.toJSON()), + otherRevocationInfos: Array.from(this.otherRevocationInfos, element => element.toJSON()) + }; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = RevocationInfoChoices; + +},{"./CertificateRevocationList.js":22,"./OtherRevocationInfoFormat.js":64,"asn1js":112,"pvutils":113}],94:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _Time = _interopRequireDefault(require("./Time.js")); + +var _Extensions = _interopRequireDefault(require("./Extensions.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC5280 + */ +class RevokedCertificate { + //********************************************************************************** + + /** + * Constructor for RevokedCertificate class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {Integer} + * @desc userCertificate + */ + this.userCertificate = (0, _pvutils.getParametersValue)(parameters, "userCertificate", RevokedCertificate.defaultValues("userCertificate")); + /** + * @type {Time} + * @desc revocationDate + */ + + this.revocationDate = (0, _pvutils.getParametersValue)(parameters, "revocationDate", RevokedCertificate.defaultValues("revocationDate")); + if ("crlEntryExtensions" in parameters) + /** + * @type {Extensions} + * @desc crlEntryExtensions + */ + this.crlEntryExtensions = (0, _pvutils.getParametersValue)(parameters, "crlEntryExtensions", RevokedCertificate.defaultValues("crlEntryExtensions")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "userCertificate": + return new asn1js.Integer(); + + case "revocationDate": + return new _Time.default(); + + case "crlEntryExtensions": + return new _Extensions.default(); + + default: + throw new Error(`Invalid member name for RevokedCertificate class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * revokedCertificates SEQUENCE OF SEQUENCE { + * userCertificate CertificateSerialNumber, + * revocationDate Time, + * crlEntryExtensions Extensions OPTIONAL + * -- if present, version MUST be v2 + * } OPTIONAL, + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [userCertificate] + * @property {string} [revocationDate] + * @property {string} [crlEntryExtensions] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [new asn1js.Integer({ + name: names.userCertificate || "userCertificate" + }), _Time.default.schema({ + names: { + utcTimeName: names.revocationDate || "revocationDate", + generalTimeName: names.revocationDate || "revocationDate" + } + }), _Extensions.default.schema({ + names: { + blockName: names.crlEntryExtensions || "crlEntryExtensions" + } + }, true)] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["userCertificate", "revocationDate", "crlEntryExtensions"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, RevokedCertificate.schema()); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for RevokedCertificate"); //endregion + //region Get internal properties from parsed schema + + this.userCertificate = asn1.result.userCertificate; + this.revocationDate = new _Time.default({ + schema: asn1.result.revocationDate + }); + if ("crlEntryExtensions" in asn1.result) this.crlEntryExtensions = new _Extensions.default({ + schema: asn1.result.crlEntryExtensions + }); //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Create array for output sequence + const outputArray = [this.userCertificate, this.revocationDate.toSchema()]; + if ("crlEntryExtensions" in this) outputArray.push(this.crlEntryExtensions.toSchema()); //endregion + //region Construct and return new ASN.1 schema for this object + + return new asn1js.Sequence({ + value: outputArray + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + const object = { + userCertificate: this.userCertificate.toJSON(), + revocationDate: this.revocationDate.toJSON + }; + if ("crlEntryExtensions" in this) object.crlEntryExtensions = this.crlEntryExtensions.toJSON(); + return object; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = RevokedCertificate; + +},{"./Extensions.js":39,"./Time.js":107,"asn1js":112,"pvutils":113}],95:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _Attribute = _interopRequireDefault(require("./Attribute.js")); + +var _PrivateKeyInfo = _interopRequireDefault(require("./PrivateKeyInfo.js")); + +var _PKCS8ShroudedKeyBag = _interopRequireDefault(require("./PKCS8ShroudedKeyBag.js")); + +var _CertBag = _interopRequireDefault(require("./CertBag.js")); + +var _CRLBag = _interopRequireDefault(require("./CRLBag.js")); + +var _SecretBag = _interopRequireDefault(require("./SecretBag.js")); + +var _SafeContents = _interopRequireDefault(require("./SafeContents.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC7292 + */ +class SafeBag { + //********************************************************************************** + + /** + * Constructor for SafeBag class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {string} + * @desc bagId + */ + this.bagId = (0, _pvutils.getParametersValue)(parameters, "bagId", SafeBag.defaultValues("bagId")); + /** + * @type {*} + * @desc bagValue + */ + + this.bagValue = (0, _pvutils.getParametersValue)(parameters, "bagValue", SafeBag.defaultValues("bagValue")); + if ("bagAttributes" in parameters) + /** + * @type {Array.} + * @desc bagAttributes + */ + this.bagAttributes = (0, _pvutils.getParametersValue)(parameters, "bagAttributes", SafeBag.defaultValues("bagAttributes")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "bagId": + return ""; + + case "bagValue": + return new asn1js.Any(); + + case "bagAttributes": + return []; + + default: + throw new Error(`Invalid member name for SafeBag class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + + + static compareWithDefault(memberName, memberValue) { + switch (memberName) { + case "bagId": + return memberValue === ""; + + case "bagValue": + return memberValue instanceof asn1js.Any; + + case "bagAttributes": + return memberValue.length === 0; + + default: + throw new Error(`Invalid member name for SafeBag class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * SafeBag ::= SEQUENCE { + * bagId BAG-TYPE.&id ({PKCS12BagSet}), + * bagValue [0] EXPLICIT BAG-TYPE.&Type({PKCS12BagSet}{@bagId}), + * bagAttributes SET OF PKCS12Attribute OPTIONAL + * } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [bagId] + * @property {string} [bagValue] + * @property {string} [bagAttributes] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [new asn1js.ObjectIdentifier({ + name: names.bagId || "bagId" + }), new asn1js.Constructed({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: [new asn1js.Any({ + name: names.bagValue || "bagValue" + })] // EXPLICIT ANY value + + }), new asn1js.Set({ + optional: true, + value: [new asn1js.Repeated({ + name: names.bagAttributes || "bagAttributes", + value: _Attribute.default.schema() + })] + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["bagId", "bagValue", "bagAttributes"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, SafeBag.schema({ + names: { + bagId: "bagId", + bagValue: "bagValue", + bagAttributes: "bagAttributes" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for SafeBag"); //endregion + //region Get internal properties from parsed schema + + this.bagId = asn1.result.bagId.valueBlock.toString(); + + switch (this.bagId) { + case "1.2.840.113549.1.12.10.1.1": + // keyBag + this.bagValue = new _PrivateKeyInfo.default({ + schema: asn1.result.bagValue + }); + break; + + case "1.2.840.113549.1.12.10.1.2": + // pkcs8ShroudedKeyBag + this.bagValue = new _PKCS8ShroudedKeyBag.default({ + schema: asn1.result.bagValue + }); + break; + + case "1.2.840.113549.1.12.10.1.3": + // certBag + this.bagValue = new _CertBag.default({ + schema: asn1.result.bagValue + }); + break; + + case "1.2.840.113549.1.12.10.1.4": + // crlBag + this.bagValue = new _CRLBag.default({ + schema: asn1.result.bagValue + }); + break; + + case "1.2.840.113549.1.12.10.1.5": + // secretBag + this.bagValue = new _SecretBag.default({ + schema: asn1.result.bagValue + }); + break; + + case "1.2.840.113549.1.12.10.1.6": + // safeContentsBag + this.bagValue = new _SafeContents.default({ + schema: asn1.result.bagValue + }); + break; + + default: + throw new Error(`Invalid "bagId" for SafeBag: ${this.bagId}`); + } + + if ("bagAttributes" in asn1.result) this.bagAttributes = Array.from(asn1.result.bagAttributes, element => new _Attribute.default({ + schema: element + })); //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Construct and return new ASN.1 schema for this object + const outputArray = [new asn1js.ObjectIdentifier({ + value: this.bagId + }), new asn1js.Constructed({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: [this.bagValue.toSchema()] + })]; + + if ("bagAttributes" in this) { + outputArray.push(new asn1js.Set({ + value: Array.from(this.bagAttributes, element => element.toSchema()) + })); + } + + return new asn1js.Sequence({ + value: outputArray + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + const output = { + bagId: this.bagId, + bagValue: this.bagValue.toJSON() + }; + if ("bagAttributes" in this) output.bagAttributes = Array.from(this.bagAttributes, element => element.toJSON()); + return output; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = SafeBag; + +},{"./Attribute.js":6,"./CRLBag.js":15,"./CertBag.js":17,"./PKCS8ShroudedKeyBag.js":68,"./PrivateKeyInfo.js":76,"./SafeContents.js":96,"./SecretBag.js":97,"asn1js":112,"pvutils":113}],96:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _SafeBag = _interopRequireDefault(require("./SafeBag.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC7292 + */ +class SafeContents { + //********************************************************************************** + + /** + * Constructor for SafeContents class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {Array.} + * @desc safeBags + */ + this.safeBags = (0, _pvutils.getParametersValue)(parameters, "safeBags", SafeContents.defaultValues("safeBags")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "safeBags": + return []; + + default: + throw new Error(`Invalid member name for SafeContents class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + + + static compareWithDefault(memberName, memberValue) { + switch (memberName) { + case "safeBags": + return memberValue.length === 0; + + default: + throw new Error(`Invalid member name for SafeContents class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * SafeContents ::= SEQUENCE OF SafeBag + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [safeBags] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [new asn1js.Repeated({ + name: names.safeBags || "", + value: _SafeBag.default.schema() + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["safeBags"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, SafeContents.schema({ + names: { + safeBags: "safeBags" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for SafeContents"); //endregion + //region Get internal properties from parsed schema + + this.safeBags = Array.from(asn1.result.safeBags, element => new _SafeBag.default({ + schema: element + })); //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Construct and return new ASN.1 schema for this object + return new asn1js.Sequence({ + value: Array.from(this.safeBags, element => element.toSchema()) + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + return { + safeBags: Array.from(this.safeBags, element => element.toJSON()) + }; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = SafeContents; + +},{"./SafeBag.js":95,"asn1js":112,"pvutils":113}],97:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC7292 + */ +class SecretBag { + //********************************************************************************** + + /** + * Constructor for SecretBag class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {string} + * @desc secretTypeId + */ + this.secretTypeId = (0, _pvutils.getParametersValue)(parameters, "secretTypeId", SecretBag.defaultValues("secretTypeId")); + /** + * @type {*} + * @desc secretValue + */ + + this.secretValue = (0, _pvutils.getParametersValue)(parameters, "secretValue", SecretBag.defaultValues("secretValue")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "secretTypeId": + return ""; + + case "secretValue": + return new asn1js.Any(); + + default: + throw new Error(`Invalid member name for SecretBag class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + + + static compareWithDefault(memberName, memberValue) { + switch (memberName) { + case "secretTypeId": + return memberValue === ""; + + case "secretValue": + return memberValue instanceof asn1js.Any; + + default: + throw new Error(`Invalid member name for SecretBag class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * SecretBag ::= SEQUENCE { + * secretTypeId BAG-TYPE.&id ({SecretTypes}), + * secretValue [0] EXPLICIT BAG-TYPE.&Type ({SecretTypes}{@secretTypeId}) + * } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [id] + * @property {string} [value] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [new asn1js.ObjectIdentifier({ + name: names.id || "id" + }), new asn1js.Constructed({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: [new asn1js.Any({ + name: names.value || "value" + })] // EXPLICIT ANY value + + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["secretTypeId", "secretValue"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, SecretBag.schema({ + names: { + id: "secretTypeId", + value: "secretValue" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for SecretBag"); //endregion + //region Get internal properties from parsed schema + + this.secretTypeId = asn1.result.secretTypeId.valueBlock.toString(); + this.secretValue = asn1.result.secretValue; //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Construct and return new ASN.1 schema for this object + return new asn1js.Sequence({ + value: [new asn1js.ObjectIdentifier({ + value: this.secretTypeId + }), new asn1js.Constructed({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: [this.secretValue.toSchema()] + })] + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + return { + secretTypeId: this.secretTypeId, + secretValue: this.secretValue.toJSON() + }; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = SecretBag; + +},{"asn1js":112,"pvutils":113}],98:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _AlgorithmIdentifier = _interopRequireDefault(require("./AlgorithmIdentifier.js")); + +var _Certificate = _interopRequireDefault(require("./Certificate.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC6960 + */ +class Signature { + //********************************************************************************** + + /** + * Constructor for Signature class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {AlgorithmIdentifier} + * @desc signatureAlgorithm + */ + this.signatureAlgorithm = (0, _pvutils.getParametersValue)(parameters, "signatureAlgorithm", Signature.defaultValues("signatureAlgorithm")); + /** + * @type {BitString} + * @desc signature + */ + + this.signature = (0, _pvutils.getParametersValue)(parameters, "signature", Signature.defaultValues("signature")); + if ("certs" in parameters) + /** + * @type {Array.} + * @desc certs + */ + this.certs = (0, _pvutils.getParametersValue)(parameters, "certs", Signature.defaultValues("certs")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "signatureAlgorithm": + return new _AlgorithmIdentifier.default(); + + case "signature": + return new asn1js.BitString(); + + case "certs": + return []; + + default: + throw new Error(`Invalid member name for Signature class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + + + static compareWithDefault(memberName, memberValue) { + switch (memberName) { + case "signatureAlgorithm": + return memberValue.algorithmId === "" && "algorithmParams" in memberValue === false; + + case "signature": + return memberValue.isEqual(Signature.defaultValues(memberName)); + + case "certs": + return memberValue.length === 0; + + default: + throw new Error(`Invalid member name for Signature class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * Signature ::= SEQUENCE { + * signatureAlgorithm AlgorithmIdentifier, + * signature BIT STRING, + * certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [signatureAlgorithm] + * @property {string} [signature] + * @property {string} [certs] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [_AlgorithmIdentifier.default.schema(names.signatureAlgorithm || {}), new asn1js.BitString({ + name: names.signature || "" + }), new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: [new asn1js.Sequence({ + value: [new asn1js.Repeated({ + name: names.certs || "", + value: _Certificate.default.schema(names.certs || {}) + })] + })] + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["signatureAlgorithm", "signature", "certs"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, Signature.schema({ + names: { + signatureAlgorithm: { + names: { + blockName: "signatureAlgorithm" + } + }, + signature: "signature", + certs: "certs" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for Signature"); //endregion + //region Get internal properties from parsed schema + + this.signatureAlgorithm = new _AlgorithmIdentifier.default({ + schema: asn1.result.signatureAlgorithm + }); + this.signature = asn1.result.signature; + if ("certs" in asn1.result) this.certs = Array.from(asn1.result.certs, element => new _Certificate.default({ + schema: element + })); //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Create array of output sequence + const outputArray = []; + outputArray.push(this.signatureAlgorithm.toSchema()); + outputArray.push(this.signature); + + if ("certs" in this) { + outputArray.push(new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: [new asn1js.Sequence({ + value: Array.from(this.certs, element => element.toSchema()) + })] + })); + } //endregion + //region Construct and return new ASN.1 schema for this object + + + return new asn1js.Sequence({ + value: outputArray + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + const _object = { + signatureAlgorithm: this.signatureAlgorithm.toJSON(), + signature: this.signature.toJSON() + }; + if ("certs" in this) _object.certs = Array.from(this.certs, element => element.toJSON()); + return _object; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = Signature; + +},{"./AlgorithmIdentifier.js":4,"./Certificate.js":19,"asn1js":112,"pvutils":113}],99:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _Attribute = _interopRequireDefault(require("./Attribute.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC5652 + */ +class SignedAndUnsignedAttributes { + //********************************************************************************** + + /** + * Constructor for SignedAndUnsignedAttributes class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {number} + * @desc type + */ + this.type = (0, _pvutils.getParametersValue)(parameters, "type", SignedAndUnsignedAttributes.defaultValues("type")); + /** + * @type {Array} + * @desc attributes + */ + + this.attributes = (0, _pvutils.getParametersValue)(parameters, "attributes", SignedAndUnsignedAttributes.defaultValues("attributes")); + /** + * @type {ArrayBuffer} + * @desc encodedValue Need to have it in order to successfully process with signature verification + */ + + this.encodedValue = (0, _pvutils.getParametersValue)(parameters, "encodedValue", SignedAndUnsignedAttributes.defaultValues("encodedValue")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "type": + return -1; + + case "attributes": + return []; + + case "encodedValue": + return new ArrayBuffer(0); + + default: + throw new Error(`Invalid member name for SignedAndUnsignedAttributes class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + + + static compareWithDefault(memberName, memberValue) { + switch (memberName) { + case "type": + return memberValue === SignedAndUnsignedAttributes.defaultValues("type"); + + case "attributes": + return memberValue.length === 0; + + case "encodedValue": + return memberValue.byteLength === 0; + + default: + throw new Error(`Invalid member name for SignedAndUnsignedAttributes class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * SignedAttributes ::= SET SIZE (1..MAX) OF Attribute + * + * UnsignedAttributes ::= SET SIZE (1..MAX) OF Attribute + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {number} [tagNumber] + * @property {string} [attributes] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Constructed({ + name: names.blockName || "", + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: names.tagNumber // "SignedAttributes" = 0, "UnsignedAttributes" = 1 + + }, + value: [new asn1js.Repeated({ + name: names.attributes || "", + value: _Attribute.default.schema() + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["attributes"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, SignedAndUnsignedAttributes.schema({ + names: { + tagNumber: this.type, + attributes: "attributes" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for SignedAndUnsignedAttributes"); //endregion + //region Get internal properties from parsed schema + + this.type = asn1.result.idBlock.tagNumber; + this.encodedValue = asn1.result.valueBeforeDecode; //region Change type from "[0]" to "SET" accordingly to standard + + const encodedView = new Uint8Array(this.encodedValue); + encodedView[0] = 0x31; //endregion + + if ("attributes" in asn1.result === false) { + if (this.type === 0) throw new Error("Wrong structure of SignedUnsignedAttributes");else return; // Not so important in case of "UnsignedAttributes" + } + + this.attributes = Array.from(asn1.result.attributes, element => new _Attribute.default({ + schema: element + })); //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + if (SignedAndUnsignedAttributes.compareWithDefault("type", this.type) || SignedAndUnsignedAttributes.compareWithDefault("attributes", this.attributes)) throw new Error("Incorrectly initialized \"SignedAndUnsignedAttributes\" class"); //region Construct and return new ASN.1 schema for this object + + return new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: this.type // "SignedAttributes" = 0, "UnsignedAttributes" = 1 + + }, + value: Array.from(this.attributes, element => element.toSchema()) + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + if (SignedAndUnsignedAttributes.compareWithDefault("type", this.type) || SignedAndUnsignedAttributes.compareWithDefault("attributes", this.attributes)) throw new Error("Incorrectly initialized \"SignedAndUnsignedAttributes\" class"); + return { + type: this.type, + attributes: Array.from(this.attributes, element => element.toJSON()) + }; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = SignedAndUnsignedAttributes; + +},{"./Attribute.js":6,"asn1js":112,"pvutils":113}],100:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.verifySCTsForCertificate = verifySCTsForCertificate; +exports.default = exports.SignedCertificateTimestamp = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _bytestreamjs = require("bytestreamjs"); + +var _common = require("./common.js"); + +var _PublicKeyInfo = _interopRequireDefault(require("./PublicKeyInfo.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } } + +function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; } + +//************************************************************************************** +class SignedCertificateTimestamp { + //********************************************************************************** + + /** + * Constructor for SignedCertificateTimestamp class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {number} + * @desc version + */ + this.version = (0, _pvutils.getParametersValue)(parameters, "version", SignedCertificateTimestamp.defaultValues("version")); + /** + * @type {ArrayBuffer} + * @desc logID + */ + + this.logID = (0, _pvutils.getParametersValue)(parameters, "logID", SignedCertificateTimestamp.defaultValues("logID")); + /** + * @type {Date} + * @desc timestamp + */ + + this.timestamp = (0, _pvutils.getParametersValue)(parameters, "timestamp", SignedCertificateTimestamp.defaultValues("timestamp")); + /** + * @type {ArrayBuffer} + * @desc extensions + */ + + this.extensions = (0, _pvutils.getParametersValue)(parameters, "extensions", SignedCertificateTimestamp.defaultValues("extensions")); + /** + * @type {string} + * @desc hashAlgorithm + */ + + this.hashAlgorithm = (0, _pvutils.getParametersValue)(parameters, "hashAlgorithm", SignedCertificateTimestamp.defaultValues("hashAlgorithm")); + /** + * @type {string} + * @desc signatureAlgorithm + */ + + this.signatureAlgorithm = (0, _pvutils.getParametersValue)(parameters, "signatureAlgorithm", SignedCertificateTimestamp.defaultValues("signatureAlgorithm")); + /** + * @type {Object} + * @desc signature + */ + + this.signature = (0, _pvutils.getParametersValue)(parameters, "signature", SignedCertificateTimestamp.defaultValues("signature")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + //region If input argument array contains "stream" + + if ("stream" in parameters) this.fromStream(parameters.stream); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "version": + return 0; + + case "logID": + case "extensions": + return new ArrayBuffer(0); + + case "timestamp": + return new Date(0); + + case "hashAlgorithm": + case "signatureAlgorithm": + return ""; + + case "signature": + return new asn1js.Any(); + + default: + throw new Error(`Invalid member name for SignedCertificateTimestamp class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + if (schema instanceof asn1js.RawData === false) throw new Error("Object's schema was not verified against input data for SignedCertificateTimestamp"); + const seqStream = new _bytestreamjs.SeqStream({ + stream: new _bytestreamjs.ByteStream({ + buffer: schema.data + }) + }); + this.fromStream(seqStream); + } //********************************************************************************** + + /** + * Convert SeqStream data into current class + * @param {!SeqStream} stream + */ + + + fromStream(stream) { + const blockLength = stream.getUint16(); + this.version = stream.getBlock(1)[0]; + + if (this.version === 0) { + this.logID = new Uint8Array(stream.getBlock(32)).buffer.slice(0); + this.timestamp = new Date((0, _pvutils.utilFromBase)(new Uint8Array(stream.getBlock(8)), 8)); //region Extensions + + const extensionsLength = stream.getUint16(); + this.extensions = new Uint8Array(stream.getBlock(extensionsLength)).buffer.slice(0); //endregion + //region Hash algorithm + + switch (stream.getBlock(1)[0]) { + case 0: + this.hashAlgorithm = "none"; + break; + + case 1: + this.hashAlgorithm = "md5"; + break; + + case 2: + this.hashAlgorithm = "sha1"; + break; + + case 3: + this.hashAlgorithm = "sha224"; + break; + + case 4: + this.hashAlgorithm = "sha256"; + break; + + case 5: + this.hashAlgorithm = "sha384"; + break; + + case 6: + this.hashAlgorithm = "sha512"; + break; + + default: + throw new Error("Object's stream was not correct for SignedCertificateTimestamp"); + } //endregion + //region Signature algorithm + + + switch (stream.getBlock(1)[0]) { + case 0: + this.signatureAlgorithm = "anonymous"; + break; + + case 1: + this.signatureAlgorithm = "rsa"; + break; + + case 2: + this.signatureAlgorithm = "dsa"; + break; + + case 3: + this.signatureAlgorithm = "ecdsa"; + break; + + default: + throw new Error("Object's stream was not correct for SignedCertificateTimestamp"); + } //endregion + //region Signature + + + const signatureLength = stream.getUint16(); + const signatureData = new Uint8Array(stream.getBlock(signatureLength)).buffer.slice(0); + const asn1 = asn1js.fromBER(signatureData); + if (asn1.offset === -1) throw new Error("Object's stream was not correct for SignedCertificateTimestamp"); + this.signature = asn1.result; //endregion + + if (blockLength !== 47 + extensionsLength + signatureLength) throw new Error("Object's stream was not correct for SignedCertificateTimestamp"); + } + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + const stream = this.toStream(); + return new asn1js.RawData({ + data: stream.stream.buffer + }); + } //********************************************************************************** + + /** + * Convert current object to SeqStream data + * @returns {SeqStream} SeqStream object + */ + + + toStream() { + const stream = new _bytestreamjs.SeqStream(); + stream.appendUint16(47 + this.extensions.byteLength + this.signature.valueBeforeDecode.byteLength); + stream.appendChar(this.version); + stream.appendView(new Uint8Array(this.logID)); + const timeBuffer = new ArrayBuffer(8); + const timeView = new Uint8Array(timeBuffer); + const baseArray = (0, _pvutils.utilToBase)(this.timestamp.valueOf(), 8); + timeView.set(new Uint8Array(baseArray), 8 - baseArray.byteLength); + stream.appendView(timeView); + stream.appendUint16(this.extensions.byteLength); + if (this.extensions.byteLength) stream.appendView(new Uint8Array(this.extensions)); + + let _hashAlgorithm; + + switch (this.hashAlgorithm.toLowerCase()) { + case "none": + _hashAlgorithm = 0; + break; + + case "md5": + _hashAlgorithm = 1; + break; + + case "sha1": + _hashAlgorithm = 2; + break; + + case "sha224": + _hashAlgorithm = 3; + break; + + case "sha256": + _hashAlgorithm = 4; + break; + + case "sha384": + _hashAlgorithm = 5; + break; + + case "sha512": + _hashAlgorithm = 6; + break; + + default: + throw new Error(`Incorrect data for hashAlgorithm: ${this.hashAlgorithm}`); + } + + stream.appendChar(_hashAlgorithm); + + let _signatureAlgorithm; + + switch (this.signatureAlgorithm.toLowerCase()) { + case "anonymous": + _signatureAlgorithm = 0; + break; + + case "rsa": + _signatureAlgorithm = 1; + break; + + case "dsa": + _signatureAlgorithm = 2; + break; + + case "ecdsa": + _signatureAlgorithm = 3; + break; + + default: + throw new Error(`Incorrect data for signatureAlgorithm: ${this.signatureAlgorithm}`); + } + + stream.appendChar(_signatureAlgorithm); + + const _signature = this.signature.toBER(false); + + stream.appendUint16(_signature.byteLength); + stream.appendView(new Uint8Array(_signature)); + return stream; + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + return { + version: this.version, + logID: (0, _pvutils.bufferToHexCodes)(this.logID), + timestamp: this.timestamp, + extensions: (0, _pvutils.bufferToHexCodes)(this.extensions), + hashAlgorithm: this.hashAlgorithm, + signatureAlgorithm: this.signatureAlgorithm, + signature: this.signature.toJSON() + }; + } //********************************************************************************** + + /** + * Verify SignedCertificateTimestamp for specific input data + * @param {Object[]} logs Array of objects with information about each CT Log (like here: https://ct.grahamedgecombe.com/logs.json) + * @param {String} logs.log_id Identifier of the CT Log encoded in BASE-64 format + * @param {String} logs.key Public key of the CT Log encoded in BASE-64 format + * @param {ArrayBuffer} data Data to verify signature against. Could be encoded Certificate or encoded PreCert + * @param {Number} [dataType=0] Type = 0 (data is encoded Certificate), type = 1 (data is encoded PreCert) + * @return {Promise} + */ + + + verify(logs, data, dataType = 0) { + var _this = this; + + return _asyncToGenerator(function* () { + //region Initial variables + let logId = (0, _pvutils.toBase64)((0, _pvutils.arrayBufferToString)(_this.logID)); + let publicKeyBase64 = null; + let publicKeyInfo; + let stream = new _bytestreamjs.SeqStream(); //endregion + //region Found and init public key + + var _iteratorNormalCompletion = true; + var _didIteratorError = false; + var _iteratorError = undefined; + + try { + for (var _iterator = logs[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { + const log = _step.value; + + if (log.log_id === logId) { + publicKeyBase64 = log.key; + break; + } + } + } catch (err) { + _didIteratorError = true; + _iteratorError = err; + } finally { + try { + if (!_iteratorNormalCompletion && _iterator.return != null) { + _iterator.return(); + } + } finally { + if (_didIteratorError) { + throw _iteratorError; + } + } + } + + if (publicKeyBase64 === null) throw new Error(`Public key not found for CT with logId: ${logId}`); + const asn1 = asn1js.fromBER((0, _pvutils.stringToArrayBuffer)((0, _pvutils.fromBase64)(publicKeyBase64))); + if (asn1.offset === -1) throw new Error(`Incorrect key value for CT Log with logId: ${logId}`); + publicKeyInfo = new _PublicKeyInfo.default({ + schema: asn1.result + }); //endregion + //region Initialize signed data block + + stream.appendChar(0x00); // sct_version + + stream.appendChar(0x00); // signature_type = certificate_timestamp + + const timeBuffer = new ArrayBuffer(8); + const timeView = new Uint8Array(timeBuffer); + const baseArray = (0, _pvutils.utilToBase)(_this.timestamp.valueOf(), 8); + timeView.set(new Uint8Array(baseArray), 8 - baseArray.byteLength); + stream.appendView(timeView); + stream.appendUint16(dataType); + if (dataType === 0) stream.appendUint24(data.byteLength); + stream.appendView(new Uint8Array(data)); + stream.appendUint16(_this.extensions.byteLength); + if (_this.extensions.byteLength !== 0) stream.appendView(new Uint8Array(_this.extensions)); //endregion + //region Perform verification + + return (0, _common.getEngine)().subtle.verifyWithPublicKey(stream._stream._buffer.slice(0, stream._length), { + valueBlock: { + valueHex: _this.signature.toBER(false) + } + }, publicKeyInfo, { + algorithmId: "" + }, "SHA-256"); //endregion + })(); + } //********************************************************************************** + + +} //************************************************************************************** + +/** + * Class from RFC6962 + */ + + +exports.SignedCertificateTimestamp = SignedCertificateTimestamp; + +class SignedCertificateTimestampList { + //********************************************************************************** + + /** + * Constructor for SignedCertificateTimestampList class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {Array.} + * @desc timestamps + */ + this.timestamps = (0, _pvutils.getParametersValue)(parameters, "timestamps", SignedCertificateTimestampList.defaultValues("timestamps")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "timestamps": + return []; + + default: + throw new Error(`Invalid member name for SignedCertificateTimestampList class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + + + static compareWithDefault(memberName, memberValue) { + switch (memberName) { + case "timestamps": + return memberValue.length === 0; + + default: + throw new Error(`Invalid member name for SignedCertificateTimestampList class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * SignedCertificateTimestampList ::= OCTET STRING + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [optional] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + if ("optional" in names === false) names.optional = false; + return new asn1js.OctetString({ + name: names.blockName || "SignedCertificateTimestampList", + optional: names.optional + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Check the schema is valid + if (schema instanceof asn1js.OctetString === false) throw new Error("Object's schema was not verified against input data for SignedCertificateTimestampList"); //endregion + //region Get internal properties from parsed schema + + const seqStream = new _bytestreamjs.SeqStream({ + stream: new _bytestreamjs.ByteStream({ + buffer: schema.valueBlock.valueHex + }) + }); + let dataLength = seqStream.getUint16(); + if (dataLength !== seqStream.length) throw new Error("Object's schema was not verified against input data for SignedCertificateTimestampList"); + + while (seqStream.length) this.timestamps.push(new SignedCertificateTimestamp({ + stream: seqStream + })); //endregion + + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Initial variables + const stream = new _bytestreamjs.SeqStream(); + let overallLength = 0; + const timestampsData = []; //endregion + //region Get overall length + + var _iteratorNormalCompletion2 = true; + var _didIteratorError2 = false; + var _iteratorError2 = undefined; + + try { + for (var _iterator2 = this.timestamps[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { + const timestamp = _step2.value; + const timestampStream = timestamp.toStream(); + timestampsData.push(timestampStream); + overallLength += timestampStream.stream.buffer.byteLength; + } //endregion + + } catch (err) { + _didIteratorError2 = true; + _iteratorError2 = err; + } finally { + try { + if (!_iteratorNormalCompletion2 && _iterator2.return != null) { + _iterator2.return(); + } + } finally { + if (_didIteratorError2) { + throw _iteratorError2; + } + } + } + + stream.appendUint16(overallLength); //region Set data from all timestamps + + for (var _i = 0, _timestampsData = timestampsData; _i < _timestampsData.length; _i++) { + const timestamp = _timestampsData[_i]; + stream.appendView(timestamp.stream.view); + } //endregion + + + return new asn1js.OctetString({ + valueHex: stream.stream.buffer.slice(0) + }); + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + return { + timestamps: Array.from(this.timestamps, element => element.toJSON()) + }; + } //********************************************************************************** + + +} //************************************************************************************** + +/** + * Verify SignedCertificateTimestamp for specific certificate content + * @param {Certificate} certificate Certificate for which verification would be performed + * @param {Certificate} issuerCertificate Certificate of the issuer of target certificate + * @param {Object[]} logs Array of objects with information about each CT Log (like here: https://ct.grahamedgecombe.com/logs.json) + * @param {String} logs.log_id Identifier of the CT Log encoded in BASE-64 format + * @param {String} logs.key Public key of the CT Log encoded in BASE-64 format + * @param {Number} [index=-1] Index of SignedCertificateTimestamp inside SignedCertificateTimestampList (for -1 would verify all) + * @return {Array} Array of verification results + */ + + +exports.default = SignedCertificateTimestampList; + +function verifySCTsForCertificate(_x, _x2, _x3) { + return _verifySCTsForCertificate.apply(this, arguments); +} //********************************************************************************** + + +function _verifySCTsForCertificate() { + _verifySCTsForCertificate = _asyncToGenerator(function* (certificate, issuerCertificate, logs, index = -1) { + //region Initial variables + let parsedValue = null; + let tbs; + let issuerId; + const stream = new _bytestreamjs.SeqStream(); + let preCert; //endregion + //region Get a "crypto" extension + + const crypto = (0, _common.getCrypto)(); + if (typeof crypto === "undefined") return Promise.reject("Unable to create WebCrypto object"); //endregion + //region Remove certificate extension + + for (let i = 0; i < certificate.extensions.length; i++) { + switch (certificate.extensions[i].extnID) { + case "1.3.6.1.4.1.11129.2.4.2": + { + parsedValue = certificate.extensions[i].parsedValue; + if (parsedValue.timestamps.length === 0) throw new Error("Nothing to verify in the certificate"); + certificate.extensions.splice(i, 1); + } + break; + + default: + } + } //endregion + //region Check we do have what to verify + + + if (parsedValue === null) throw new Error("No SignedCertificateTimestampList extension in the specified certificate"); //endregion + //region Prepare modifier TBS value + + tbs = certificate.encodeTBS().toBER(false); //endregion + //region Initialize "issuer_key_hash" value + + issuerId = yield crypto.digest({ + name: "SHA-256" + }, new Uint8Array(issuerCertificate.subjectPublicKeyInfo.toSchema().toBER(false))); //endregion + //region Make final "PreCert" value + + stream.appendView(new Uint8Array(issuerId)); + stream.appendUint24(tbs.byteLength); + stream.appendView(new Uint8Array(tbs)); + preCert = stream._stream._buffer.slice(0, stream._length); //endregion + //region Call verification function for specified index + + if (index === -1) { + const verifyArray = []; + var _iteratorNormalCompletion3 = true; + var _didIteratorError3 = false; + var _iteratorError3 = undefined; + + try { + for (var _iterator3 = parsedValue.timestamps[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) { + const timestamp = _step3.value; + const verifyResult = yield timestamp.verify(logs, preCert, 1); + verifyArray.push(verifyResult); + } + } catch (err) { + _didIteratorError3 = true; + _iteratorError3 = err; + } finally { + try { + if (!_iteratorNormalCompletion3 && _iterator3.return != null) { + _iterator3.return(); + } + } finally { + if (_didIteratorError3) { + throw _iteratorError3; + } + } + } + + return verifyArray; + } + + if (index >= parsedValue.timestamps.length) index = parsedValue.timestamps.length - 1; + return [yield parsedValue.timestamps[index].verify(logs, preCert, 1)]; //endregion + }); + return _verifySCTsForCertificate.apply(this, arguments); +} + +},{"./PublicKeyInfo.js":78,"./common.js":110,"asn1js":112,"bytestreamjs":1,"pvutils":113}],101:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _common = require("./common.js"); + +var _AlgorithmIdentifier = _interopRequireDefault(require("./AlgorithmIdentifier.js")); + +var _EncapsulatedContentInfo = _interopRequireDefault(require("./EncapsulatedContentInfo.js")); + +var _Certificate = _interopRequireDefault(require("./Certificate.js")); + +var _CertificateRevocationList = _interopRequireDefault(require("./CertificateRevocationList.js")); + +var _OtherRevocationInfoFormat = _interopRequireDefault(require("./OtherRevocationInfoFormat.js")); + +var _SignerInfo = _interopRequireDefault(require("./SignerInfo.js")); + +var _CertificateSet = _interopRequireDefault(require("./CertificateSet.js")); + +var _RevocationInfoChoices = _interopRequireDefault(require("./RevocationInfoChoices.js")); + +var _IssuerAndSerialNumber = _interopRequireDefault(require("./IssuerAndSerialNumber.js")); + +var _TSTInfo = _interopRequireDefault(require("./TSTInfo.js")); + +var _CertificateChainValidationEngine = _interopRequireDefault(require("./CertificateChainValidationEngine.js")); + +var _BasicOCSPResponse = _interopRequireDefault(require("./BasicOCSPResponse.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); } + +function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } + +function _iterableToArrayLimit(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } + +function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } + +//************************************************************************************** + +/** + * Class from RFC5652 + */ +class SignedData { + //********************************************************************************** + + /** + * Constructor for SignedData class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {number} + * @desc version + */ + this.version = (0, _pvutils.getParametersValue)(parameters, "version", SignedData.defaultValues("version")); + /** + * @type {Array.} + * @desc digestAlgorithms + */ + + this.digestAlgorithms = (0, _pvutils.getParametersValue)(parameters, "digestAlgorithms", SignedData.defaultValues("digestAlgorithms")); + /** + * @type {EncapsulatedContentInfo} + * @desc encapContentInfo + */ + + this.encapContentInfo = (0, _pvutils.getParametersValue)(parameters, "encapContentInfo", SignedData.defaultValues("encapContentInfo")); + if ("certificates" in parameters) + /** + * @type {Array.} + * @desc certificates + */ + this.certificates = (0, _pvutils.getParametersValue)(parameters, "certificates", SignedData.defaultValues("certificates")); + if ("crls" in parameters) + /** + * @type {Array.} + * @desc crls + */ + this.crls = (0, _pvutils.getParametersValue)(parameters, "crls", SignedData.defaultValues("crls")); + if ("ocsps" in parameters) + /** + * @type {Array.} + * @desc crls + */ + this.ocsps = (0, _pvutils.getParametersValue)(parameters, "ocsps", SignedData.defaultValues("ocsps")); + /** + * @type {Array.} + * @desc signerInfos + */ + + this.signerInfos = (0, _pvutils.getParametersValue)(parameters, "signerInfos", SignedData.defaultValues("signerInfos")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "version": + return 0; + + case "digestAlgorithms": + return []; + + case "encapContentInfo": + return new _EncapsulatedContentInfo.default(); + + case "certificates": + return []; + + case "crls": + return []; + + case "ocsps": + return []; + + case "signerInfos": + return []; + + default: + throw new Error(`Invalid member name for SignedData class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + + + static compareWithDefault(memberName, memberValue) { + switch (memberName) { + case "version": + return memberValue === SignedData.defaultValues("version"); + + case "encapContentInfo": + return new _EncapsulatedContentInfo.default(); + + case "digestAlgorithms": + case "certificates": + case "crls": + case "ocsps": + case "signerInfos": + return memberValue.length === 0; + + default: + throw new Error(`Invalid member name for SignedData class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * SignedData ::= SEQUENCE { + * version CMSVersion, + * digestAlgorithms DigestAlgorithmIdentifiers, + * encapContentInfo EncapsulatedContentInfo, + * certificates [0] IMPLICIT CertificateSet OPTIONAL, + * crls [1] IMPLICIT RevocationInfoChoices OPTIONAL, + * signerInfos SignerInfos } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [optional] + * @property {string} [digestAlgorithms] + * @property {string} [encapContentInfo] + * @property {string} [certificates] + * @property {string} [crls] + * @property {string} [signerInfos] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + if ("optional" in names === false) names.optional = false; + return new asn1js.Sequence({ + name: names.blockName || "SignedData", + optional: names.optional, + value: [new asn1js.Integer({ + name: names.version || "SignedData.version" + }), new asn1js.Set({ + value: [new asn1js.Repeated({ + name: names.digestAlgorithms || "SignedData.digestAlgorithms", + value: _AlgorithmIdentifier.default.schema() + })] + }), _EncapsulatedContentInfo.default.schema(names.encapContentInfo || { + names: { + blockName: "SignedData.encapContentInfo" + } + }), new asn1js.Constructed({ + name: names.certificates || "SignedData.certificates", + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: _CertificateSet.default.schema().valueBlock.value + }), // IMPLICIT CertificateSet + new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + + }, + value: _RevocationInfoChoices.default.schema(names.crls || { + names: { + crls: "SignedData.crls" + } + }).valueBlock.value + }), // IMPLICIT RevocationInfoChoices + new asn1js.Set({ + value: [new asn1js.Repeated({ + name: names.signerInfos || "SignedData.signerInfos", + value: _SignerInfo.default.schema() + })] + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["SignedData.version", "SignedData.digestAlgorithms", "SignedData.encapContentInfo", "SignedData.certificates", "SignedData.crls", "SignedData.signerInfos"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, SignedData.schema()); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for SignedData"); //endregion + //region Get internal properties from parsed schema + + this.version = asn1.result["SignedData.version"].valueBlock.valueDec; + if ("SignedData.digestAlgorithms" in asn1.result) // Could be empty SET of digest algorithms + this.digestAlgorithms = Array.from(asn1.result["SignedData.digestAlgorithms"], algorithm => new _AlgorithmIdentifier.default({ + schema: algorithm + })); + this.encapContentInfo = new _EncapsulatedContentInfo.default({ + schema: asn1.result["SignedData.encapContentInfo"] + }); + + if ("SignedData.certificates" in asn1.result) { + const certificateSet = new _CertificateSet.default({ + schema: new asn1js.Set({ + value: asn1.result["SignedData.certificates"].valueBlock.value + }) + }); + this.certificates = certificateSet.certificates.slice(0); // Copy all just for making comfortable access + } + + if ("SignedData.crls" in asn1.result) { + this.crls = Array.from(asn1.result["SignedData.crls"], crl => { + if (crl.idBlock.tagClass === 1) return new _CertificateRevocationList.default({ + schema: crl + }); //region Create SEQUENCE from [1] + + crl.idBlock.tagClass = 1; // UNIVERSAL + + crl.idBlock.tagNumber = 16; // SEQUENCE + //endregion + + return new _OtherRevocationInfoFormat.default({ + schema: crl + }); + }); + } + + if ("SignedData.signerInfos" in asn1.result) // Could be empty SET SignerInfos + this.signerInfos = Array.from(asn1.result["SignedData.signerInfos"], signerInfoSchema => new _SignerInfo.default({ + schema: signerInfoSchema + })); //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema(encodeFlag = false) { + //region Create array for output sequence + const outputArray = []; + outputArray.push(new asn1js.Integer({ + value: this.version + })); //region Create array of digest algorithms + + outputArray.push(new asn1js.Set({ + value: Array.from(this.digestAlgorithms, algorithm => algorithm.toSchema(encodeFlag)) + })); //endregion + + outputArray.push(this.encapContentInfo.toSchema()); + + if ("certificates" in this) { + const certificateSet = new _CertificateSet.default({ + certificates: this.certificates + }); + const certificateSetSchema = certificateSet.toSchema(); + outputArray.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, + tagNumber: 0 + }, + value: certificateSetSchema.valueBlock.value + })); + } + + if ("crls" in this) { + outputArray.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + + }, + value: Array.from(this.crls, crl => { + if (crl instanceof _OtherRevocationInfoFormat.default) { + const crlSchema = crl.toSchema(encodeFlag); + crlSchema.idBlock.tagClass = 3; + crlSchema.idBlock.tagNumber = 1; + return crlSchema; + } + + return crl.toSchema(encodeFlag); + }) + })); + } //region Create array of signer infos + + + outputArray.push(new asn1js.Set({ + value: Array.from(this.signerInfos, signerInfo => signerInfo.toSchema(encodeFlag)) + })); //endregion + //endregion + //region Construct and return new ASN.1 schema for this object + + return new asn1js.Sequence({ + value: outputArray + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + const _object = { + version: this.version, + digestAlgorithms: Array.from(this.digestAlgorithms, algorithm => algorithm.toJSON()), + encapContentInfo: this.encapContentInfo.toJSON() + }; + if ("certificates" in this) _object.certificates = Array.from(this.certificates, certificate => certificate.toJSON()); + if ("crls" in this) _object.crls = Array.from(this.crls, crl => crl.toJSON()); + _object.signerInfos = Array.from(this.signerInfos, signerInfo => signerInfo.toJSON()); + return _object; + } //********************************************************************************** + + /** + * Verify current SignedData value + * @param {Object} [param={}] + * @param {Number} [param.signer = -1] Index of the signer which information we need to verify + * @param {ArrayBuffer} [param.data=new ArrayBuffer(0)] + * @param {Array.} [param.trustedCerts=[]] + * @param {Date} [param.checkDate=new Date()] + * @param {Boolean} [param.checkChain=false] + * @param {Boolean} [param.extendedMode=false] + * @param {?Function} [findOrigin=null] + * @param {?Function} [findIssuer=null] + */ + + + verify({ + signer = -1, + data = new ArrayBuffer(0), + trustedCerts = [], + checkDate = new Date(), + checkChain = false, + extendedMode = false, + passedWhenNotRevValues = false, + findOrigin = null, + findIssuer = null + } = {}) { + //region Global variables + let sequence = Promise.resolve(); + let messageDigestValue = new ArrayBuffer(0); + let shaAlgorithm = ""; + let signerCertificate = {}; + let timestampSerial = null; + let certificatePath = []; + const engine = (0, _common.getEngine)(); //endregion + //region Get a "crypto" extension + + const crypto = (0, _common.getCrypto)(); + if (typeof crypto === "undefined") return Promise.reject("Unable to create WebCrypto object"); //endregion + //region Get a signer number + + if (signer === -1) { + if (extendedMode) { + return Promise.reject({ + date: checkDate, + code: 1, + message: "Unable to get signer index from input parameters", + signatureVerified: null, + signerCertificate: null, + signerCertificateVerified: null + }); + } + + return Promise.reject("Unable to get signer index from input parameters"); + } //endregion + //region Check that certificates field was included in signed data + + + if ("certificates" in this === false) { + if (extendedMode) { + return Promise.reject({ + date: checkDate, + code: 2, + message: "No certificates attached to this signed data", + signatureVerified: null, + signerCertificate: null, + signerCertificateVerified: null + }); + } + + return Promise.reject("No certificates attached to this signed data"); + } //endregion + //region Find a certificate for specified signer + + + if (this.signerInfos[signer].sid instanceof _IssuerAndSerialNumber.default) { + sequence = sequence.then(() => { + var _iteratorNormalCompletion = true; + var _didIteratorError = false; + var _iteratorError = undefined; + + try { + for (var _iterator = this.certificates[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { + const certificate = _step.value; + if (certificate instanceof _Certificate.default === false) continue; + + if (certificate.issuer.isEqual(this.signerInfos[signer].sid.issuer) && certificate.serialNumber.isEqual(this.signerInfos[signer].sid.serialNumber)) { + signerCertificate = certificate; + return Promise.resolve(); + } + } + } catch (err) { + _didIteratorError = true; + _iteratorError = err; + } finally { + try { + if (!_iteratorNormalCompletion && _iterator.return != null) { + _iterator.return(); + } + } finally { + if (_didIteratorError) { + throw _iteratorError; + } + } + } + + if (extendedMode) { + return Promise.reject({ + date: checkDate, + code: 3, + message: "Unable to find signer certificate", + signatureVerified: null, + signerCertificate: null, + signerCertificateVerified: null + }); + } + + return Promise.reject("Unable to find signer certificate"); + }); + } else // Find by SubjectKeyIdentifier + { + sequence = sequence.then(() => Promise.all(Array.from(this.certificates.filter(certificate => certificate instanceof _Certificate.default), certificate => crypto.digest({ + name: "sha-1" + }, new Uint8Array(certificate.subjectPublicKeyInfo.subjectPublicKey.valueBlock.valueHex)))).then(results => { + var _iteratorNormalCompletion2 = true; + var _didIteratorError2 = false; + var _iteratorError2 = undefined; + + try { + for (var _iterator2 = this.certificates.entries()[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { + const _step2$value = _slicedToArray(_step2.value, 2), + index = _step2$value[0], + certificate = _step2$value[1]; + + if (certificate instanceof _Certificate.default === false) continue; + + if ((0, _pvutils.isEqualBuffer)(results[index], this.signerInfos[signer].sid.valueBlock.valueHex)) { + signerCertificate = certificate; + return Promise.resolve(); + } + } + } catch (err) { + _didIteratorError2 = true; + _iteratorError2 = err; + } finally { + try { + if (!_iteratorNormalCompletion2 && _iterator2.return != null) { + _iterator2.return(); + } + } finally { + if (_didIteratorError2) { + throw _iteratorError2; + } + } + } + + if (extendedMode) { + return Promise.reject({ + date: checkDate, + code: 3, + message: "Unable to find signer certificate", + signatureVerified: null, + signerCertificate: null, + signerCertificateVerified: null + }); + } + + return Promise.reject("Unable to find signer certificate"); + }, () => { + if (extendedMode) { + return Promise.reject({ + date: checkDate, + code: 3, + message: "Unable to find signer certificate", + signatureVerified: null, + signerCertificate: null, + signerCertificateVerified: null + }); + } + + return Promise.reject("Unable to find signer certificate"); + })); + } //endregion + //region Verify internal digest in case of "tSTInfo" content type + + + sequence = sequence.then(() => { + if (this.encapContentInfo.eContentType === "1.2.840.113549.1.9.16.1.4") { + //region Check "eContent" precense + if ("eContent" in this.encapContentInfo === false) return false; //endregion + //region Initialize TST_INFO value + + const asn1 = asn1js.fromBER(this.encapContentInfo.eContent.valueBlock.valueHex); + let tstInfo; + + try { + tstInfo = new _TSTInfo.default({ + schema: asn1.result + }); + } catch (ex) { + return false; + } //endregion + //region Change "checkDate" and append "timestampSerial" + + + checkDate = tstInfo.genTime; + timestampSerial = tstInfo.serialNumber.valueBlock.valueHex; //endregion + //region Check that we do have detached data content + + if (data.byteLength === 0) { + if (extendedMode) { + return Promise.reject({ + date: checkDate, + code: 4, + message: "Missed detached data input array", + signatureVerified: null, + signerCertificate, + signerCertificateVerified: null + }); + } + + return Promise.reject("Missed detached data input array"); + } //endregion + + + return tstInfo.verify({ + data + }); + } + + return true; + }); //endregion + //region Make additional verification for signer's certificate + + function checkCA(cert) { + /// Certificate to find CA flag for + //region Do not include signer's certificate + if (cert.issuer.isEqual(signerCertificate.issuer) === true && cert.serialNumber.isEqual(signerCertificate.serialNumber) === true) return null; //endregion + + let isCA = false; + + if ("extensions" in cert) { + var _iteratorNormalCompletion3 = true; + var _didIteratorError3 = false; + var _iteratorError3 = undefined; + + try { + for (var _iterator3 = cert.extensions[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) { + const extension = _step3.value; + + if (extension.extnID === "2.5.29.19") // BasicConstraints + { + if ("cA" in extension.parsedValue) { + if (extension.parsedValue.cA === true) isCA = true; + } + } + } + } catch (err) { + _didIteratorError3 = true; + _iteratorError3 = err; + } finally { + try { + if (!_iteratorNormalCompletion3 && _iterator3.return != null) { + _iterator3.return(); + } + } finally { + if (_didIteratorError3) { + throw _iteratorError3; + } + } + } + } + + if (isCA) return cert; + return null; + } + + if (checkChain) { + sequence = sequence.then(result => { + //region Verify result of previous operation + if (result === false) return false; //endregion + + const promiseResults = Array.from(this.certificates.filter(certificate => certificate instanceof _Certificate.default), certificate => checkCA(certificate)); + const certificateChainValidationEngineParameters = { + checkDate, + certs: Array.from(promiseResults.filter(_result => _result !== null)), + trustedCerts + }; + if (findIssuer !== null) certificateChainValidationEngineParameters.findIssuer = findIssuer; + if (findOrigin !== null) certificateChainValidationEngineParameters.findOrigin = findOrigin; + const certificateChainEngine = new _CertificateChainValidationEngine.default(certificateChainValidationEngineParameters); + certificateChainEngine.certs.push(signerCertificate); + + if ("crls" in this) { + var _iteratorNormalCompletion4 = true; + var _didIteratorError4 = false; + var _iteratorError4 = undefined; + + try { + for (var _iterator4 = this.crls[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) { + const crl = _step4.value; + if ("thisUpdate" in crl) certificateChainEngine.crls.push(crl);else // Assumed "revocation value" has "OtherRevocationInfoFormat" + { + if (crl.otherRevInfoFormat === "1.3.6.1.5.5.7.48.1.1") // Basic OCSP response + certificateChainEngine.ocsps.push(new _BasicOCSPResponse.default({ + schema: crl.otherRevInfo + })); + } + } + } catch (err) { + _didIteratorError4 = true; + _iteratorError4 = err; + } finally { + try { + if (!_iteratorNormalCompletion4 && _iterator4.return != null) { + _iterator4.return(); + } + } finally { + if (_didIteratorError4) { + throw _iteratorError4; + } + } + } + } + + if ("ocsps" in this) certificateChainEngine.ocsps.push(...this.ocsps); + return certificateChainEngine.verify({ + passedWhenNotRevValues + }).then(verificationResult => { + if ("certificatePath" in verificationResult) certificatePath = verificationResult.certificatePath; + if (verificationResult.result === true) return Promise.resolve(true); + + if (extendedMode) { + return Promise.reject({ + date: checkDate, + code: 5, + message: `Validation of signer's certificate failed: ${verificationResult.resultMessage}`, + signatureVerified: null, + signerCertificate, + signerCertificateVerified: false + }); + } + + return Promise.reject("Validation of signer's certificate failed"); + }, error => { + if (extendedMode) { + return Promise.reject({ + date: checkDate, + code: 5, + message: `Validation of signer's certificate failed with error: ${error instanceof Object ? error.resultMessage : error}`, + signatureVerified: null, + signerCertificate, + signerCertificateVerified: false + }); + } + + return Promise.reject(`Validation of signer's certificate failed with error: ${error instanceof Object ? error.resultMessage : error}`); + }); + }); + } //endregion + //region Find signer's hashing algorithm + + + sequence = sequence.then(result => { + //region Verify result of previous operation + if (result === false) return false; //endregion + + const signerInfoHashAlgorithm = (0, _common.getAlgorithmByOID)(this.signerInfos[signer].digestAlgorithm.algorithmId); + + if ("name" in signerInfoHashAlgorithm === false) { + if (extendedMode) { + return Promise.reject({ + date: checkDate, + code: 7, + message: `Unsupported signature algorithm: ${this.signerInfos[signer].digestAlgorithm.algorithmId}`, + signatureVerified: null, + signerCertificate, + signerCertificateVerified: true + }); + } + + return Promise.reject(`Unsupported signature algorithm: ${this.signerInfos[signer].digestAlgorithm.algorithmId}`); + } + + shaAlgorithm = signerInfoHashAlgorithm.name; + return true; + }); //endregion + //region Create correct data block for verification + + sequence = sequence.then(result => { + //region Verify result of previous operation + if (result === false) return false; //endregion + + if ("eContent" in this.encapContentInfo) // Attached data + { + if (this.encapContentInfo.eContent.idBlock.tagClass === 1 && this.encapContentInfo.eContent.idBlock.tagNumber === 4) { + if (this.encapContentInfo.eContent.idBlock.isConstructed === false) data = this.encapContentInfo.eContent.valueBlock.valueHex;else { + var _iteratorNormalCompletion5 = true; + var _didIteratorError5 = false; + var _iteratorError5 = undefined; + + try { + for (var _iterator5 = this.encapContentInfo.eContent.valueBlock.value[Symbol.iterator](), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) { + const contentValue = _step5.value; + data = (0, _pvutils.utilConcatBuf)(data, contentValue.valueBlock.valueHex); + } + } catch (err) { + _didIteratorError5 = true; + _iteratorError5 = err; + } finally { + try { + if (!_iteratorNormalCompletion5 && _iterator5.return != null) { + _iterator5.return(); + } + } finally { + if (_didIteratorError5) { + throw _iteratorError5; + } + } + } + } + } else data = this.encapContentInfo.eContent.valueBlock.valueBeforeDecode; + } else // Detached data + { + if (data.byteLength === 0) // Check that "data" already provided by function parameter + { + if (extendedMode) { + return Promise.reject({ + date: checkDate, + code: 8, + message: "Missed detached data input array", + signatureVerified: null, + signerCertificate, + signerCertificateVerified: true + }); + } + + return Promise.reject("Missed detached data input array"); + } + } + + if ("signedAttrs" in this.signerInfos[signer]) { + //region Check mandatory attributes + let foundContentType = false; + let foundMessageDigest = false; + var _iteratorNormalCompletion6 = true; + var _didIteratorError6 = false; + var _iteratorError6 = undefined; + + try { + for (var _iterator6 = this.signerInfos[signer].signedAttrs.attributes[Symbol.iterator](), _step6; !(_iteratorNormalCompletion6 = (_step6 = _iterator6.next()).done); _iteratorNormalCompletion6 = true) { + const attribute = _step6.value; + //region Check that "content-type" attribute exists + if (attribute.type === "1.2.840.113549.1.9.3") foundContentType = true; //endregion + //region Check that "message-digest" attribute exists + + if (attribute.type === "1.2.840.113549.1.9.4") { + foundMessageDigest = true; + messageDigestValue = attribute.values[0].valueBlock.valueHex; + } //endregion + //region Speed-up searching + + + if (foundContentType && foundMessageDigest) break; //endregion + } + } catch (err) { + _didIteratorError6 = true; + _iteratorError6 = err; + } finally { + try { + if (!_iteratorNormalCompletion6 && _iterator6.return != null) { + _iterator6.return(); + } + } finally { + if (_didIteratorError6) { + throw _iteratorError6; + } + } + } + + if (foundContentType === false) { + if (extendedMode) { + return Promise.reject({ + date: checkDate, + code: 9, + message: "Attribute \"content-type\" is a mandatory attribute for \"signed attributes\"", + signatureVerified: null, + signerCertificate, + signerCertificateVerified: true + }); + } + + return Promise.reject("Attribute \"content-type\" is a mandatory attribute for \"signed attributes\""); + } + + if (foundMessageDigest === false) { + if (extendedMode) { + return Promise.reject({ + date: checkDate, + code: 10, + message: "Attribute \"message-digest\" is a mandatory attribute for \"signed attributes\"", + signatureVerified: null, + signerCertificate, + signerCertificateVerified: true + }); + } + + return Promise.reject("Attribute \"message-digest\" is a mandatory attribute for \"signed attributes\""); + } //endregion + + } + + return true; + }); //endregion + //region Verify "message-digest" attribute in case of "signedAttrs" + + sequence = sequence.then(result => { + //region Verify result of previous operation + if (result === false) return false; //endregion + + if ("signedAttrs" in this.signerInfos[signer]) return crypto.digest(shaAlgorithm, new Uint8Array(data)); + return true; + }).then( + /** + * @param {ArrayBuffer} result + */ + result => { + //region Verify result of previous operation + if (result === false) return false; //endregion + + if ("signedAttrs" in this.signerInfos[signer]) { + if ((0, _pvutils.isEqualBuffer)(result, messageDigestValue)) { + data = this.signerInfos[signer].signedAttrs.encodedValue; + return true; + } + + return false; + } + + return true; + }); //endregion + + sequence = sequence.then(result => { + //region Verify result of previous operation + if (result === false) return false; //endregion + + return engine.subtle.verifyWithPublicKey(data, this.signerInfos[signer].signature, signerCertificate.subjectPublicKeyInfo, signerCertificate.signatureAlgorithm, shaAlgorithm); + }); //region Make a final result + + sequence = sequence.then(result => { + if (extendedMode) { + return { + date: checkDate, + code: 14, + message: "", + signatureVerified: result, + signerCertificate, + timestampSerial, + signerCertificateVerified: true, + certificatePath + }; + } + + return result; + }, error => { + if (extendedMode) { + if ("code" in error) return Promise.reject(error); + return Promise.reject({ + date: checkDate, + code: 15, + message: `Error during verification: ${error.message}`, + signatureVerified: null, + signerCertificate, + timestampSerial, + signerCertificateVerified: true + }); + } + + return Promise.reject(error); + }); //endregion + + return sequence; + } //********************************************************************************** + + /** + * Signing current SignedData + * @param {key} privateKey Private key for "subjectPublicKeyInfo" structure + * @param {number} signerIndex Index number (starting from 0) of signer index to make signature for + * @param {string} [hashAlgorithm="SHA-1"] Hashing algorithm. Default SHA-1 + * @param {ArrayBuffer} [data] Detached data + * @returns {*} + */ + + + sign(privateKey, signerIndex, hashAlgorithm = "SHA-1", data = new ArrayBuffer(0)) { + //region Initial checking + if (typeof privateKey === "undefined") return Promise.reject("Need to provide a private key for signing"); //endregion + //region Initial variables + + let sequence = Promise.resolve(); + let parameters; + const engine = (0, _common.getEngine)(); //endregion + //region Simple check for supported algorithm + + const hashAlgorithmOID = (0, _common.getOIDByAlgorithm)({ + name: hashAlgorithm + }); + if (hashAlgorithmOID === "") return Promise.reject(`Unsupported hash algorithm: ${hashAlgorithm}`); //endregion + //region Append information about hash algorithm + + if (this.digestAlgorithms.filter(algorithm => algorithm.algorithmId === hashAlgorithmOID).length === 0) { + this.digestAlgorithms.push(new _AlgorithmIdentifier.default({ + algorithmId: hashAlgorithmOID, + algorithmParams: new asn1js.Null() + })); + } + + this.signerInfos[signerIndex].digestAlgorithm = new _AlgorithmIdentifier.default({ + algorithmId: hashAlgorithmOID, + algorithmParams: new asn1js.Null() + }); //endregion + //region Get a "default parameters" for current algorithm and set correct signature algorithm + + sequence = sequence.then(() => engine.subtle.getSignatureParameters(privateKey, hashAlgorithm)); + sequence = sequence.then(result => { + parameters = result.parameters; + this.signerInfos[signerIndex].signatureAlgorithm = result.signatureAlgorithm; + }); //endregion + //region Create TBS data for signing + + sequence = sequence.then(() => { + if ("signedAttrs" in this.signerInfos[signerIndex]) { + if (this.signerInfos[signerIndex].signedAttrs.encodedValue.byteLength !== 0) data = this.signerInfos[signerIndex].signedAttrs.encodedValue;else { + data = this.signerInfos[signerIndex].signedAttrs.toSchema(true).toBER(false); //region Change type from "[0]" to "SET" acordingly to standard + + const view = new Uint8Array(data); + view[0] = 0x31; //endregion + } + } else { + if ("eContent" in this.encapContentInfo) // Attached data + { + if (this.encapContentInfo.eContent.idBlock.tagClass === 1 && this.encapContentInfo.eContent.idBlock.tagNumber === 4) { + if (this.encapContentInfo.eContent.idBlock.isConstructed === false) data = this.encapContentInfo.eContent.valueBlock.valueHex;else { + var _iteratorNormalCompletion7 = true; + var _didIteratorError7 = false; + var _iteratorError7 = undefined; + + try { + for (var _iterator7 = this.encapContentInfo.eContent.valueBlock.value[Symbol.iterator](), _step7; !(_iteratorNormalCompletion7 = (_step7 = _iterator7.next()).done); _iteratorNormalCompletion7 = true) { + const content = _step7.value; + data = (0, _pvutils.utilConcatBuf)(data, content.valueBlock.valueHex); + } + } catch (err) { + _didIteratorError7 = true; + _iteratorError7 = err; + } finally { + try { + if (!_iteratorNormalCompletion7 && _iterator7.return != null) { + _iterator7.return(); + } + } finally { + if (_didIteratorError7) { + throw _iteratorError7; + } + } + } + } + } else data = this.encapContentInfo.eContent.valueBlock.valueBeforeDecode; + } else // Detached data + { + if (data.byteLength === 0) // Check that "data" already provided by function parameter + return Promise.reject("Missed detached data input array"); + } + } + + return Promise.resolve(); + }); //endregion + //region Signing TBS data on provided private key + + sequence = sequence.then(() => engine.subtle.signWithPrivateKey(data, privateKey, parameters)); + sequence = sequence.then(result => { + this.signerInfos[signerIndex].signature = new asn1js.OctetString({ + valueHex: result + }); + return result; + }); //endregion + + return sequence; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = SignedData; + +},{"./AlgorithmIdentifier.js":4,"./BasicOCSPResponse.js":13,"./Certificate.js":19,"./CertificateChainValidationEngine.js":20,"./CertificateRevocationList.js":22,"./CertificateSet.js":23,"./EncapsulatedContentInfo.js":33,"./IssuerAndSerialNumber.js":44,"./OtherRevocationInfoFormat.js":64,"./RevocationInfoChoices.js":93,"./SignerInfo.js":102,"./TSTInfo.js":106,"./common.js":110,"asn1js":112,"pvutils":113}],102:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _AlgorithmIdentifier = _interopRequireDefault(require("./AlgorithmIdentifier.js")); + +var _SignedAndUnsignedAttributes = _interopRequireDefault(require("./SignedAndUnsignedAttributes.js")); + +var _IssuerAndSerialNumber = _interopRequireDefault(require("./IssuerAndSerialNumber.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC5652 + */ +class SignerInfo { + //********************************************************************************** + + /** + * Constructor for SignerInfo class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {string} + * @desc version + */ + this.version = (0, _pvutils.getParametersValue)(parameters, "version", SignerInfo.defaultValues("version")); + /** + * @type {Object} + * @desc sid + */ + + this.sid = (0, _pvutils.getParametersValue)(parameters, "sid", SignerInfo.defaultValues("sid")); + /** + * @type {AlgorithmIdentifier} + * @desc digestAlgorithm + */ + + this.digestAlgorithm = (0, _pvutils.getParametersValue)(parameters, "digestAlgorithm", SignerInfo.defaultValues("digestAlgorithm")); + if ("signedAttrs" in parameters) + /** + * @type {SignedAndUnsignedAttributes} + * @desc signedAttrs + */ + this.signedAttrs = (0, _pvutils.getParametersValue)(parameters, "signedAttrs", SignerInfo.defaultValues("signedAttrs")); + /** + * @type {AlgorithmIdentifier} + * @desc digestAlgorithm + */ + + this.signatureAlgorithm = (0, _pvutils.getParametersValue)(parameters, "signatureAlgorithm", SignerInfo.defaultValues("signatureAlgorithm")); + /** + * @type {OctetString} + * @desc signature + */ + + this.signature = (0, _pvutils.getParametersValue)(parameters, "signature", SignerInfo.defaultValues("signature")); + if ("unsignedAttrs" in parameters) + /** + * @type {SignedAndUnsignedAttributes} + * @desc unsignedAttrs + */ + this.unsignedAttrs = (0, _pvutils.getParametersValue)(parameters, "unsignedAttrs", SignerInfo.defaultValues("unsignedAttrs")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "version": + return 0; + + case "sid": + return new asn1js.Any(); + + case "digestAlgorithm": + return new _AlgorithmIdentifier.default(); + + case "signedAttrs": + return new _SignedAndUnsignedAttributes.default({ + type: 0 + }); + + case "signatureAlgorithm": + return new _AlgorithmIdentifier.default(); + + case "signature": + return new asn1js.OctetString(); + + case "unsignedAttrs": + return new _SignedAndUnsignedAttributes.default({ + type: 1 + }); + + default: + throw new Error(`Invalid member name for SignerInfo class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + + + static compareWithDefault(memberName, memberValue) { + switch (memberName) { + case "version": + return SignerInfo.defaultValues("version") === memberValue; + + case "sid": + return memberValue instanceof asn1js.Any; + + case "digestAlgorithm": + if (memberValue instanceof _AlgorithmIdentifier.default === false) return false; + return memberValue.isEqual(SignerInfo.defaultValues("digestAlgorithm")); + + case "signedAttrs": + return _SignedAndUnsignedAttributes.default.compareWithDefault("type", memberValue.type) && _SignedAndUnsignedAttributes.default.compareWithDefault("attributes", memberValue.attributes) && _SignedAndUnsignedAttributes.default.compareWithDefault("encodedValue", memberValue.encodedValue); + + case "signatureAlgorithm": + if (memberValue instanceof _AlgorithmIdentifier.default === false) return false; + return memberValue.isEqual(SignerInfo.defaultValues("signatureAlgorithm")); + + case "signature": + case "unsignedAttrs": + return _SignedAndUnsignedAttributes.default.compareWithDefault("type", memberValue.type) && _SignedAndUnsignedAttributes.default.compareWithDefault("attributes", memberValue.attributes) && _SignedAndUnsignedAttributes.default.compareWithDefault("encodedValue", memberValue.encodedValue); + + default: + throw new Error(`Invalid member name for SignerInfo class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * SignerInfo ::= SEQUENCE { + * version CMSVersion, + * sid SignerIdentifier, + * digestAlgorithm DigestAlgorithmIdentifier, + * signedAttrs [0] IMPLICIT SignedAttributes OPTIONAL, + * signatureAlgorithm SignatureAlgorithmIdentifier, + * signature SignatureValue, + * unsignedAttrs [1] IMPLICIT UnsignedAttributes OPTIONAL } + * + * SignerIdentifier ::= CHOICE { + * issuerAndSerialNumber IssuerAndSerialNumber, + * subjectKeyIdentifier [0] SubjectKeyIdentifier } + * + * SubjectKeyIdentifier ::= OCTET STRING + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [version] + * @property {string} [sid] + * @property {string} [digestAlgorithm] + * @property {string} [signedAttrs] + * @property {string} [signatureAlgorithm] + * @property {string} [signature] + * @property {string} [unsignedAttrs] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: "SignerInfo", + value: [new asn1js.Integer({ + name: names.version || "SignerInfo.version" + }), new asn1js.Choice({ + value: [_IssuerAndSerialNumber.default.schema(names.sid || { + names: { + blockName: "SignerInfo.sid" + } + }), new asn1js.Constructed({ + optional: true, + name: names.sid || "SignerInfo.sid", + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: [new asn1js.OctetString()] + })] + }), _AlgorithmIdentifier.default.schema(names.digestAlgorithm || { + names: { + blockName: "SignerInfo.digestAlgorithm" + } + }), _SignedAndUnsignedAttributes.default.schema(names.signedAttrs || { + names: { + blockName: "SignerInfo.signedAttrs", + tagNumber: 0 + } + }), _AlgorithmIdentifier.default.schema(names.signatureAlgorithm || { + names: { + blockName: "SignerInfo.signatureAlgorithm" + } + }), new asn1js.OctetString({ + name: names.signature || "SignerInfo.signature" + }), _SignedAndUnsignedAttributes.default.schema(names.unsignedAttrs || { + names: { + blockName: "SignerInfo.unsignedAttrs", + tagNumber: 1 + } + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["SignerInfo.version", "SignerInfo.sid", "SignerInfo.digestAlgorithm", "SignerInfo.signedAttrs", "SignerInfo.signatureAlgorithm", "SignerInfo.signature", "SignerInfo.unsignedAttrs"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, SignerInfo.schema()); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for SignerInfo"); //endregion + //region Get internal properties from parsed schema + + this.version = asn1.result["SignerInfo.version"].valueBlock.valueDec; + const currentSid = asn1.result["SignerInfo.sid"]; + if (currentSid.idBlock.tagClass === 1) this.sid = new _IssuerAndSerialNumber.default({ + schema: currentSid + });else this.sid = currentSid; + this.digestAlgorithm = new _AlgorithmIdentifier.default({ + schema: asn1.result["SignerInfo.digestAlgorithm"] + }); + if ("SignerInfo.signedAttrs" in asn1.result) this.signedAttrs = new _SignedAndUnsignedAttributes.default({ + type: 0, + schema: asn1.result["SignerInfo.signedAttrs"] + }); + this.signatureAlgorithm = new _AlgorithmIdentifier.default({ + schema: asn1.result["SignerInfo.signatureAlgorithm"] + }); + this.signature = asn1.result["SignerInfo.signature"]; + if ("SignerInfo.unsignedAttrs" in asn1.result) this.unsignedAttrs = new _SignedAndUnsignedAttributes.default({ + type: 1, + schema: asn1.result["SignerInfo.unsignedAttrs"] + }); //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + if (SignerInfo.compareWithDefault("sid", this.sid)) throw new Error("Incorrectly initialized \"SignerInfo\" class"); //region Create array for output sequence + + const outputArray = []; + outputArray.push(new asn1js.Integer({ + value: this.version + })); + if (this.sid instanceof _IssuerAndSerialNumber.default) outputArray.push(this.sid.toSchema());else outputArray.push(this.sid); + outputArray.push(this.digestAlgorithm.toSchema()); + + if ("signedAttrs" in this) { + if (SignerInfo.compareWithDefault("signedAttrs", this.signedAttrs) === false) outputArray.push(this.signedAttrs.toSchema()); + } + + outputArray.push(this.signatureAlgorithm.toSchema()); + outputArray.push(this.signature); + + if ("unsignedAttrs" in this) { + if (SignerInfo.compareWithDefault("unsignedAttrs", this.unsignedAttrs) === false) outputArray.push(this.unsignedAttrs.toSchema()); + } //endregion + //region Construct and return new ASN.1 schema for this object + + + return new asn1js.Sequence({ + value: outputArray + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + if (SignerInfo.compareWithDefault("sid", this.sid)) throw new Error("Incorrectly initialized \"SignerInfo\" class"); + const _object = { + version: this.version + }; + if (!(this.sid instanceof asn1js.Any)) _object.sid = this.sid.toJSON(); + _object.digestAlgorithm = this.digestAlgorithm.toJSON(); + if (SignerInfo.compareWithDefault("signedAttrs", this.signedAttrs) === false) _object.signedAttrs = this.signedAttrs.toJSON(); + _object.signatureAlgorithm = this.signatureAlgorithm.toJSON(); + _object.signature = this.signature.toJSON(); + if (SignerInfo.compareWithDefault("unsignedAttrs", this.unsignedAttrs) === false) _object.unsignedAttrs = this.unsignedAttrs.toJSON(); + return _object; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = SignerInfo; + +},{"./AlgorithmIdentifier.js":4,"./IssuerAndSerialNumber.js":44,"./SignedAndUnsignedAttributes.js":99,"asn1js":112,"pvutils":113}],103:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _CertID = _interopRequireDefault(require("./CertID.js")); + +var _Extension = _interopRequireDefault(require("./Extension.js")); + +var _Extensions = _interopRequireDefault(require("./Extensions.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC6960 + */ +class SingleResponse { + //********************************************************************************** + + /** + * Constructor for SingleResponse class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {CertID} + * @desc certID + */ + this.certID = (0, _pvutils.getParametersValue)(parameters, "certID", SingleResponse.defaultValues("certID")); + /** + * @type {Object} + * @desc certStatus + */ + + this.certStatus = (0, _pvutils.getParametersValue)(parameters, "certStatus", SingleResponse.defaultValues("certStatus")); + /** + * @type {Date} + * @desc thisUpdate + */ + + this.thisUpdate = (0, _pvutils.getParametersValue)(parameters, "thisUpdate", SingleResponse.defaultValues("thisUpdate")); + if ("nextUpdate" in parameters) + /** + * @type {Date} + * @desc nextUpdate + */ + this.nextUpdate = (0, _pvutils.getParametersValue)(parameters, "nextUpdate", SingleResponse.defaultValues("nextUpdate")); + if ("singleExtensions" in parameters) + /** + * @type {Array.} + * @desc singleExtensions + */ + this.singleExtensions = (0, _pvutils.getParametersValue)(parameters, "singleExtensions", SingleResponse.defaultValues("singleExtensions")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "certID": + return new _CertID.default(); + + case "certStatus": + return {}; + + case "thisUpdate": + case "nextUpdate": + return new Date(0, 0, 0); + + case "singleExtensions": + return []; + + default: + throw new Error(`Invalid member name for SingleResponse class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + + + static compareWithDefault(memberName, memberValue) { + switch (memberName) { + case "certID": + // noinspection OverlyComplexBooleanExpressionJS + return _CertID.default.compareWithDefault("hashAlgorithm", memberValue.hashAlgorithm) && _CertID.default.compareWithDefault("issuerNameHash", memberValue.issuerNameHash) && _CertID.default.compareWithDefault("issuerKeyHash", memberValue.issuerKeyHash) && _CertID.default.compareWithDefault("serialNumber", memberValue.serialNumber); + + case "certStatus": + return Object.keys(memberValue).length === 0; + + case "thisUpdate": + case "nextUpdate": + return memberValue === SingleResponse.defaultValues(memberName); + + default: + throw new Error(`Invalid member name for SingleResponse class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * SingleResponse ::= SEQUENCE { + * certID CertID, + * certStatus CertStatus, + * thisUpdate GeneralizedTime, + * nextUpdate [0] EXPLICIT GeneralizedTime OPTIONAL, + * singleExtensions [1] EXPLICIT Extensions OPTIONAL } + * + * CertStatus ::= CHOICE { + * good [0] IMPLICIT NULL, + * revoked [1] IMPLICIT RevokedInfo, + * unknown [2] IMPLICIT UnknownInfo } + * + * RevokedInfo ::= SEQUENCE { + * revocationTime GeneralizedTime, + * revocationReason [0] EXPLICIT CRLReason OPTIONAL } + * + * UnknownInfo ::= NULL + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [certID] + * @property {string} [certStatus] + * @property {string} [thisUpdate] + * @property {string} [nextUpdate] + * @property {string} [singleExtensions] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [_CertID.default.schema(names.certID || {}), new asn1js.Choice({ + value: [new asn1js.Primitive({ + name: names.certStatus || "", + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + lenBlockLength: 1 // The length contains one byte 0x00 + + }), // IMPLICIT NULL (no "valueBlock") + new asn1js.Constructed({ + name: names.certStatus || "", + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + + }, + value: [new asn1js.GeneralizedTime(), new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: [new asn1js.Enumerated()] + })] + }), new asn1js.Primitive({ + name: names.certStatus || "", + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 2 // [2] + + }, + lenBlock: { + length: 1 + } + }) // IMPLICIT NULL (no "valueBlock") + ] + }), new asn1js.GeneralizedTime({ + name: names.thisUpdate || "" + }), new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: [new asn1js.GeneralizedTime({ + name: names.nextUpdate || "" + })] + }), new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + + }, + value: [_Extensions.default.schema(names.singleExtensions || {})] + }) // EXPLICIT SEQUENCE value + ] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["certID", "certStatus", "thisUpdate", "nextUpdate", "singleExtensions"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, SingleResponse.schema({ + names: { + certID: { + names: { + blockName: "certID" + } + }, + certStatus: "certStatus", + thisUpdate: "thisUpdate", + nextUpdate: "nextUpdate", + singleExtensions: { + names: { + blockName: "singleExtensions" + } + } + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for SingleResponse"); //endregion + //region Get internal properties from parsed schema + + this.certID = new _CertID.default({ + schema: asn1.result.certID + }); + this.certStatus = asn1.result.certStatus; + this.thisUpdate = asn1.result.thisUpdate.toDate(); + if ("nextUpdate" in asn1.result) this.nextUpdate = asn1.result.nextUpdate.toDate(); + if ("singleExtensions" in asn1.result) this.singleExtensions = Array.from(asn1.result.singleExtensions.valueBlock.value, element => new _Extension.default({ + schema: element + })); //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Create value array for output sequence + const outputArray = []; + outputArray.push(this.certID.toSchema()); + outputArray.push(this.certStatus); + outputArray.push(new asn1js.GeneralizedTime({ + valueDate: this.thisUpdate + })); + + if ("nextUpdate" in this) { + outputArray.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: [new asn1js.GeneralizedTime({ + valueDate: this.nextUpdate + })] + })); + } + + if ("singleExtensions" in this) { + outputArray.push(new asn1js.Sequence({ + value: Array.from(this.singleExtensions, element => element.toSchema()) + })); + } //endregion + //region Construct and return new ASN.1 schema for this object + + + return new asn1js.Sequence({ + value: outputArray + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + const _object = { + certID: this.certID.toJSON(), + certStatus: this.certStatus.toJSON(), + thisUpdate: this.thisUpdate + }; + if ("nextUpdate" in this) _object.nextUpdate = this.nextUpdate; + if ("singleExtensions" in this) _object.singleExtensions = Array.from(this.singleExtensions, element => element.toJSON()); + return _object; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = SingleResponse; + +},{"./CertID.js":18,"./Extension.js":38,"./Extensions.js":39,"asn1js":112,"pvutils":113}],104:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _Attribute = _interopRequireDefault(require("./Attribute.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC5280 + */ +class SubjectDirectoryAttributes { + //********************************************************************************** + + /** + * Constructor for SubjectDirectoryAttributes class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {Array.} + * @desc attributes + */ + this.attributes = (0, _pvutils.getParametersValue)(parameters, "attributes", SubjectDirectoryAttributes.defaultValues("attributes")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "attributes": + return []; + + default: + throw new Error(`Invalid member name for SubjectDirectoryAttributes class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * SubjectDirectoryAttributes ::= SEQUENCE SIZE (1..MAX) OF Attribute + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [utcTimeName] Name for "utcTimeName" choice + * @property {string} [generalTimeName] Name for "generalTimeName" choice + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "", + value: [new asn1js.Repeated({ + name: names.attributes || "", + value: _Attribute.default.schema() + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["attributes"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, SubjectDirectoryAttributes.schema({ + names: { + attributes: "attributes" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for SubjectDirectoryAttributes"); //endregion + //region Get internal properties from parsed schema + + this.attributes = Array.from(asn1.result.attributes, element => new _Attribute.default({ + schema: element + })); //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Construct and return new ASN.1 schema for this object + return new asn1js.Sequence({ + value: Array.from(this.attributes, element => element.toSchema()) + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + return { + attributes: Array.from(this.attributes, element => element.toJSON()) + }; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = SubjectDirectoryAttributes; + +},{"./Attribute.js":6,"asn1js":112,"pvutils":113}],105:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _GeneralName = _interopRequireDefault(require("./GeneralName.js")); + +var _Request = _interopRequireDefault(require("./Request.js")); + +var _Extension = _interopRequireDefault(require("./Extension.js")); + +var _Extensions = _interopRequireDefault(require("./Extensions.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC6960 + */ +class TBSRequest { + //********************************************************************************** + + /** + * Constructor for TBSRequest class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {ArrayBuffer} + * @desc tbs + */ + this.tbs = (0, _pvutils.getParametersValue)(parameters, "tbs", TBSRequest.defaultValues("tbs")); + if ("version" in parameters) + /** + * @type {number} + * @desc version + */ + this.version = (0, _pvutils.getParametersValue)(parameters, "version", TBSRequest.defaultValues("version")); + if ("requestorName" in parameters) + /** + * @type {GeneralName} + * @desc requestorName + */ + this.requestorName = (0, _pvutils.getParametersValue)(parameters, "requestorName", TBSRequest.defaultValues("requestorName")); + /** + * @type {Array.} + * @desc requestList + */ + + this.requestList = (0, _pvutils.getParametersValue)(parameters, "requestList", TBSRequest.defaultValues("requestList")); + if ("requestExtensions" in parameters) + /** + * @type {Array.} + * @desc requestExtensions + */ + this.requestExtensions = (0, _pvutils.getParametersValue)(parameters, "requestExtensions", TBSRequest.defaultValues("requestExtensions")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "tbs": + return new ArrayBuffer(0); + + case "version": + return 0; + + case "requestorName": + return new _GeneralName.default(); + + case "requestList": + case "requestExtensions": + return []; + + default: + throw new Error(`Invalid member name for TBSRequest class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + + + static compareWithDefault(memberName, memberValue) { + switch (memberName) { + case "tbs": + return memberValue.byteLength === 0; + + case "version": + return memberValue === TBSRequest.defaultValues(memberName); + + case "requestorName": + return memberValue.type === _GeneralName.default.defaultValues("type") && Object.keys(memberValue.value).length === 0; + + case "requestList": + case "requestExtensions": + return memberValue.length === 0; + + default: + throw new Error(`Invalid member name for TBSRequest class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * TBSRequest ::= SEQUENCE { + * version [0] EXPLICIT Version DEFAULT v1, + * requestorName [1] EXPLICIT GeneralName OPTIONAL, + * requestList SEQUENCE OF Request, + * requestExtensions [2] EXPLICIT Extensions OPTIONAL } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [TBSRequestVersion] + * @property {string} [requestorName] + * @property {string} [requestList] + * @property {string} [requests] + * @property {string} [requestNames] + * @property {string} [extensions] + * @property {string} [requestExtensions] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "TBSRequest", + value: [new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: [new asn1js.Integer({ + name: names.TBSRequestVersion || "TBSRequest.version" + })] + }), new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + + }, + value: [_GeneralName.default.schema(names.requestorName || { + names: { + blockName: "TBSRequest.requestorName" + } + })] + }), new asn1js.Sequence({ + name: names.requestList || "TBSRequest.requestList", + value: [new asn1js.Repeated({ + name: names.requests || "TBSRequest.requests", + value: _Request.default.schema(names.requestNames || {}) + })] + }), new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 2 // [2] + + }, + value: [_Extensions.default.schema(names.extensions || { + names: { + blockName: names.requestExtensions || "TBSRequest.requestExtensions" + } + })] + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["TBSRequest", "TBSRequest.version", "TBSRequest.requestorName", "TBSRequest.requests", "TBSRequest.requestExtensions"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, TBSRequest.schema()); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for TBSRequest"); //endregion + //region Get internal properties from parsed schema + + this.tbs = asn1.result.TBSRequest.valueBeforeDecode; + if ("TBSRequest.version" in asn1.result) this.version = asn1.result["TBSRequest.version"].valueBlock.valueDec; + if ("TBSRequest.requestorName" in asn1.result) this.requestorName = new _GeneralName.default({ + schema: asn1.result["TBSRequest.requestorName"] + }); + this.requestList = Array.from(asn1.result["TBSRequest.requests"], element => new _Request.default({ + schema: element + })); + if ("TBSRequest.requestExtensions" in asn1.result) this.requestExtensions = Array.from(asn1.result["TBSRequest.requestExtensions"].valueBlock.value, element => new _Extension.default({ + schema: element + })); //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @param {boolean} encodeFlag If param equal to false then create TBS schema via decoding stored value. In othe case create TBS schema via assembling from TBS parts. + * @returns {Object} asn1js object + */ + + + toSchema(encodeFlag = false) { + //region Decode stored TBS value + let tbsSchema; + + if (encodeFlag === false) { + if (this.tbs.byteLength === 0) // No stored TBS part + return TBSRequest.schema(); + tbsSchema = asn1js.fromBER(this.tbs).result; + } //endregion + //region Create TBS schema via assembling from TBS parts + else { + const outputArray = []; + + if ("version" in this) { + outputArray.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: [new asn1js.Integer({ + value: this.version + })] + })); + } + + if ("requestorName" in this) { + outputArray.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + + }, + value: [this.requestorName.toSchema()] + })); + } + + outputArray.push(new asn1js.Sequence({ + value: Array.from(this.requestList, element => element.toSchema()) + })); + + if ("requestExtensions" in this) { + outputArray.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 2 // [2] + + }, + value: [new asn1js.Sequence({ + value: Array.from(this.requestExtensions, element => element.toSchema()) + })] + })); + } + + tbsSchema = new asn1js.Sequence({ + value: outputArray + }); + } //endregion + //region Construct and return new ASN.1 schema for this object + + + return tbsSchema; //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + const _object = {}; + if ("version" in this) _object.version = this.version; + if ("requestorName" in this) _object.requestorName = this.requestorName.toJSON(); + _object.requestList = Array.from(this.requestList, element => element.toJSON()); + if ("requestExtensions" in this) _object.requestExtensions = Array.from(this.requestExtensions, element => element.toJSON()); + return _object; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = TBSRequest; + +},{"./Extension.js":38,"./Extensions.js":39,"./GeneralName.js":40,"./Request.js":90,"asn1js":112,"pvutils":113}],106:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _common = require("./common.js"); + +var _MessageImprint = _interopRequireDefault(require("./MessageImprint.js")); + +var _Accuracy = _interopRequireDefault(require("./Accuracy.js")); + +var _GeneralName = _interopRequireDefault(require("./GeneralName.js")); + +var _Extension = _interopRequireDefault(require("./Extension.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC3161 + */ +class TSTInfo { + //********************************************************************************** + + /** + * Constructor for TSTInfo class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {number} + * @desc version + */ + this.version = (0, _pvutils.getParametersValue)(parameters, "version", TSTInfo.defaultValues("version")); + /** + * @type {string} + * @desc policy + */ + + this.policy = (0, _pvutils.getParametersValue)(parameters, "policy", TSTInfo.defaultValues("policy")); + /** + * @type {MessageImprint} + * @desc messageImprint + */ + + this.messageImprint = (0, _pvutils.getParametersValue)(parameters, "messageImprint", TSTInfo.defaultValues("messageImprint")); + /** + * @type {Integer} + * @desc serialNumber + */ + + this.serialNumber = (0, _pvutils.getParametersValue)(parameters, "serialNumber", TSTInfo.defaultValues("serialNumber")); + /** + * @type {Date} + * @desc genTime + */ + + this.genTime = (0, _pvutils.getParametersValue)(parameters, "genTime", TSTInfo.defaultValues("genTime")); + if ("accuracy" in parameters) + /** + * @type {Accuracy} + * @desc accuracy + */ + this.accuracy = (0, _pvutils.getParametersValue)(parameters, "accuracy", TSTInfo.defaultValues("accuracy")); + if ("ordering" in parameters) + /** + * @type {boolean} + * @desc ordering + */ + this.ordering = (0, _pvutils.getParametersValue)(parameters, "ordering", TSTInfo.defaultValues("ordering")); + if ("nonce" in parameters) + /** + * @type {Integer} + * @desc nonce + */ + this.nonce = (0, _pvutils.getParametersValue)(parameters, "nonce", TSTInfo.defaultValues("nonce")); + if ("tsa" in parameters) + /** + * @type {GeneralName} + * @desc tsa + */ + this.tsa = (0, _pvutils.getParametersValue)(parameters, "tsa", TSTInfo.defaultValues("tsa")); + if ("extensions" in parameters) + /** + * @type {Array.} + * @desc extensions + */ + this.extensions = (0, _pvutils.getParametersValue)(parameters, "extensions", TSTInfo.defaultValues("extensions")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "version": + return 0; + + case "policy": + return ""; + + case "messageImprint": + return new _MessageImprint.default(); + + case "serialNumber": + return new asn1js.Integer(); + + case "genTime": + return new Date(0, 0, 0); + + case "accuracy": + return new _Accuracy.default(); + + case "ordering": + return false; + + case "nonce": + return new asn1js.Integer(); + + case "tsa": + return new _GeneralName.default(); + + case "extensions": + return []; + + default: + throw new Error(`Invalid member name for TSTInfo class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + + + static compareWithDefault(memberName, memberValue) { + switch (memberName) { + case "version": + case "policy": + case "genTime": + case "ordering": + return memberValue === TSTInfo.defaultValues(memberName); + + case "messageImprint": + return _MessageImprint.default.compareWithDefault("hashAlgorithm", memberValue.hashAlgorithm) && _MessageImprint.default.compareWithDefault("hashedMessage", memberValue.hashedMessage); + + case "serialNumber": + case "nonce": + return memberValue.isEqual(TSTInfo.defaultValues(memberName)); + + case "accuracy": + return _Accuracy.default.compareWithDefault("seconds", memberValue.seconds) && _Accuracy.default.compareWithDefault("millis", memberValue.millis) && _Accuracy.default.compareWithDefault("micros", memberValue.micros); + + case "tsa": + return _GeneralName.default.compareWithDefault("type", memberValue.type) && _GeneralName.default.compareWithDefault("value", memberValue.value); + + case "extensions": + return memberValue.length === 0; + + default: + throw new Error(`Invalid member name for TSTInfo class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * TSTInfo ::= SEQUENCE { + * version INTEGER { v1(1) }, + * policy TSAPolicyId, + * messageImprint MessageImprint, + * serialNumber INTEGER, + * genTime GeneralizedTime, + * accuracy Accuracy OPTIONAL, + * ordering BOOLEAN DEFAULT FALSE, + * nonce INTEGER OPTIONAL, + * tsa [0] GeneralName OPTIONAL, + * extensions [1] IMPLICIT Extensions OPTIONAL } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [version] + * @property {string} [policy] + * @property {string} [messageImprint] + * @property {string} [serialNumber] + * @property {string} [genTime] + * @property {string} [accuracy] + * @property {string} [ordering] + * @property {string} [nonce] + * @property {string} [tsa] + * @property {string} [extensions] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "TSTInfo", + value: [new asn1js.Integer({ + name: names.version || "TSTInfo.version" + }), new asn1js.ObjectIdentifier({ + name: names.policy || "TSTInfo.policy" + }), _MessageImprint.default.schema(names.messageImprint || { + names: { + blockName: "TSTInfo.messageImprint" + } + }), new asn1js.Integer({ + name: names.serialNumber || "TSTInfo.serialNumber" + }), new asn1js.GeneralizedTime({ + name: names.genTime || "TSTInfo.genTime" + }), _Accuracy.default.schema(names.accuracy || { + names: { + blockName: "TSTInfo.accuracy" + } + }), new asn1js.Boolean({ + name: names.ordering || "TSTInfo.ordering", + optional: true + }), new asn1js.Integer({ + name: names.nonce || "TSTInfo.nonce", + optional: true + }), new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: [_GeneralName.default.schema(names.tsa || { + names: { + blockName: "TSTInfo.tsa" + } + })] + }), new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + + }, + value: [new asn1js.Repeated({ + name: names.extensions || "TSTInfo.extensions", + value: _Extension.default.schema(names.extension || {}) + })] + }) // IMPLICIT Extensions + ] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["TSTInfo.version", "TSTInfo.policy", "TSTInfo.messageImprint", "TSTInfo.serialNumber", "TSTInfo.genTime", "TSTInfo.accuracy", "TSTInfo.ordering", "TSTInfo.nonce", "TSTInfo.tsa", "TSTInfo.extensions"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, TSTInfo.schema()); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for TSTInfo"); //endregion + //region Get internal properties from parsed schema + + this.version = asn1.result["TSTInfo.version"].valueBlock.valueDec; + this.policy = asn1.result["TSTInfo.policy"].valueBlock.toString(); + this.messageImprint = new _MessageImprint.default({ + schema: asn1.result["TSTInfo.messageImprint"] + }); + this.serialNumber = asn1.result["TSTInfo.serialNumber"]; + this.genTime = asn1.result["TSTInfo.genTime"].toDate(); + if ("TSTInfo.accuracy" in asn1.result) this.accuracy = new _Accuracy.default({ + schema: asn1.result["TSTInfo.accuracy"] + }); + if ("TSTInfo.ordering" in asn1.result) this.ordering = asn1.result["TSTInfo.ordering"].valueBlock.value; + if ("TSTInfo.nonce" in asn1.result) this.nonce = asn1.result["TSTInfo.nonce"]; + if ("TSTInfo.tsa" in asn1.result) this.tsa = new _GeneralName.default({ + schema: asn1.result["TSTInfo.tsa"] + }); + if ("TSTInfo.extensions" in asn1.result) this.extensions = Array.from(asn1.result["TSTInfo.extensions"], element => new _Extension.default({ + schema: element + })); //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Create array for output sequence + const outputArray = []; + outputArray.push(new asn1js.Integer({ + value: this.version + })); + outputArray.push(new asn1js.ObjectIdentifier({ + value: this.policy + })); + outputArray.push(this.messageImprint.toSchema()); + outputArray.push(this.serialNumber); + outputArray.push(new asn1js.GeneralizedTime({ + valueDate: this.genTime + })); + if ("accuracy" in this) outputArray.push(this.accuracy.toSchema()); + if ("ordering" in this) outputArray.push(new asn1js.Boolean({ + value: this.ordering + })); + if ("nonce" in this) outputArray.push(this.nonce); + + if ("tsa" in this) { + outputArray.push(new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: [this.tsa.toSchema()] + })); + } //region Create array of extensions + + + if ("extensions" in this) { + outputArray.push(new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + + }, + value: Array.from(this.extensions, element => element.toSchema()) + })); + } //endregion + //endregion + //region Construct and return new ASN.1 schema for this object + + + return new asn1js.Sequence({ + value: outputArray + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + const _object = { + version: this.version, + policy: this.policy, + messageImprint: this.messageImprint.toJSON(), + serialNumber: this.serialNumber.toJSON(), + genTime: this.genTime + }; + if ("accuracy" in this) _object.accuracy = this.accuracy.toJSON(); + if ("ordering" in this) _object.ordering = this.ordering; + if ("nonce" in this) _object.nonce = this.nonce.toJSON(); + if ("tsa" in this) _object.tsa = this.tsa.toJSON(); + if ("extensions" in this) _object.extensions = Array.from(this.extensions, element => element.toJSON()); + return _object; + } //********************************************************************************** + + /** + * Verify current TST Info value + * @param {{data: ArrayBuffer, notBefore: Date, notAfter: Date}} parameters Input parameters + * @returns {Promise} + */ + + + verify(parameters = {}) { + //region Initial variables + let sequence = Promise.resolve(); + let data; + let notBefore = null; + let notAfter = null; //endregion + //region Get a "crypto" extension + + const crypto = (0, _common.getCrypto)(); + if (typeof crypto === "undefined") return Promise.reject("Unable to create WebCrypto object"); //endregion + //region Get initial parameters + + if ("data" in parameters) data = parameters.data;else return Promise.reject("\"data\" is a mandatory attribute for TST_INFO verification"); + if ("notBefore" in parameters) notBefore = parameters.notBefore; + if ("notAfter" in parameters) notAfter = parameters.notAfter; //endregion + //region Check date + + if (notBefore !== null) { + if (this.genTime < notBefore) return Promise.reject("Generation time for TSTInfo object is less than notBefore value"); + } + + if (notAfter !== null) { + if (this.genTime > notAfter) return Promise.reject("Generation time for TSTInfo object is more than notAfter value"); + } //endregion + //region Find hashing algorithm + + + const shaAlgorithm = (0, _common.getAlgorithmByOID)(this.messageImprint.hashAlgorithm.algorithmId); + if ("name" in shaAlgorithm === false) return Promise.reject(`Unsupported signature algorithm: ${this.messageImprint.hashAlgorithm.algorithmId}`); //endregion + //region Calculate message digest for input "data" buffer + // noinspection JSCheckFunctionSignatures + + sequence = sequence.then(() => crypto.digest(shaAlgorithm.name, new Uint8Array(data))).then(result => (0, _pvutils.isEqualBuffer)(result, this.messageImprint.hashedMessage.valueBlock.valueHex)); //endregion + + return sequence; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = TSTInfo; + +},{"./Accuracy.js":3,"./Extension.js":38,"./GeneralName.js":40,"./MessageImprint.js":53,"./common.js":110,"asn1js":112,"pvutils":113}],107:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC5280 + */ +class Time { + //********************************************************************************** + + /** + * Constructor for Time class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + * @property {number} [type] 0 - UTCTime; 1 - GeneralizedTime; 2 - empty value + * @property {Date} [value] Value of the TIME class + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {number} + * @desc 0 - UTCTime; 1 - GeneralizedTime; 2 - empty value + */ + this.type = (0, _pvutils.getParametersValue)(parameters, "type", Time.defaultValues("type")); + /** + * @type {Date} + * @desc Value of the TIME class + */ + + this.value = (0, _pvutils.getParametersValue)(parameters, "value", Time.defaultValues("value")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "type": + return 0; + + case "value": + return new Date(0, 0, 0); + + default: + throw new Error(`Invalid member name for Time class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * Time ::= CHOICE { + * utcTime UTCTime, + * generalTime GeneralizedTime } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @param {boolean} optional Flag that current schema should be optional + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}, optional = false) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [utcTimeName] Name for "utcTimeName" choice + * @property {string} [generalTimeName] Name for "generalTimeName" choice + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Choice({ + optional, + value: [new asn1js.UTCTime({ + name: names.utcTimeName || "" + }), new asn1js.GeneralizedTime({ + name: names.generalTimeName || "" + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["utcTimeName", "generalTimeName"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, Time.schema({ + names: { + utcTimeName: "utcTimeName", + generalTimeName: "generalTimeName" + } + })); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for Time"); //endregion + //region Get internal properties from parsed schema + + if ("utcTimeName" in asn1.result) { + this.type = 0; + this.value = asn1.result.utcTimeName.toDate(); + } + + if ("generalTimeName" in asn1.result) { + this.type = 1; + this.value = asn1.result.generalTimeName.toDate(); + } //endregion + + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Construct and return new ASN.1 schema for this object + let result = {}; + if (this.type === 0) result = new asn1js.UTCTime({ + valueDate: this.value + }); + if (this.type === 1) result = new asn1js.GeneralizedTime({ + valueDate: this.value + }); + return result; //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + return { + type: this.type, + value: this.value + }; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = Time; + +},{"asn1js":112,"pvutils":113}],108:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _MessageImprint = _interopRequireDefault(require("./MessageImprint.js")); + +var _Extension = _interopRequireDefault(require("./Extension.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC3161 + */ +class TimeStampReq { + //********************************************************************************** + + /** + * Constructor for TimeStampReq class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {number} + * @desc version + */ + this.version = (0, _pvutils.getParametersValue)(parameters, "version", TimeStampReq.defaultValues("version")); + /** + * @type {MessageImprint} + * @desc messageImprint + */ + + this.messageImprint = (0, _pvutils.getParametersValue)(parameters, "messageImprint", TimeStampReq.defaultValues("messageImprint")); + if ("reqPolicy" in parameters) + /** + * @type {string} + * @desc reqPolicy + */ + this.reqPolicy = (0, _pvutils.getParametersValue)(parameters, "reqPolicy", TimeStampReq.defaultValues("reqPolicy")); + if ("nonce" in parameters) + /** + * @type {Integer} + * @desc nonce + */ + this.nonce = (0, _pvutils.getParametersValue)(parameters, "nonce", TimeStampReq.defaultValues("nonce")); + if ("certReq" in parameters) + /** + * @type {boolean} + * @desc certReq + */ + this.certReq = (0, _pvutils.getParametersValue)(parameters, "certReq", TimeStampReq.defaultValues("certReq")); + if ("extensions" in parameters) + /** + * @type {Array.} + * @desc extensions + */ + this.extensions = (0, _pvutils.getParametersValue)(parameters, "extensions", TimeStampReq.defaultValues("extensions")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "version": + return 0; + + case "messageImprint": + return new _MessageImprint.default(); + + case "reqPolicy": + return ""; + + case "nonce": + return new asn1js.Integer(); + + case "certReq": + return false; + + case "extensions": + return []; + + default: + throw new Error(`Invalid member name for TimeStampReq class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + + + static compareWithDefault(memberName, memberValue) { + switch (memberName) { + case "version": + case "reqPolicy": + case "certReq": + return memberValue === TimeStampReq.defaultValues(memberName); + + case "messageImprint": + return _MessageImprint.default.compareWithDefault("hashAlgorithm", memberValue.hashAlgorithm) && _MessageImprint.default.compareWithDefault("hashedMessage", memberValue.hashedMessage); + + case "nonce": + return memberValue.isEqual(TimeStampReq.defaultValues(memberName)); + + case "extensions": + return memberValue.length === 0; + + default: + throw new Error(`Invalid member name for TimeStampReq class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * TimeStampReq ::= SEQUENCE { + * version INTEGER { v1(1) }, + * messageImprint MessageImprint, + * reqPolicy TSAPolicyId OPTIONAL, + * nonce INTEGER OPTIONAL, + * certReq BOOLEAN DEFAULT FALSE, + * extensions [0] IMPLICIT Extensions OPTIONAL } + * + * TSAPolicyId ::= OBJECT IDENTIFIER + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [type] + * @property {string} [setName] + * @property {string} [values] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "TimeStampReq", + value: [new asn1js.Integer({ + name: names.version || "TimeStampReq.version" + }), _MessageImprint.default.schema(names.messageImprint || { + names: { + blockName: "TimeStampReq.messageImprint" + } + }), new asn1js.ObjectIdentifier({ + name: names.reqPolicy || "TimeStampReq.reqPolicy", + optional: true + }), new asn1js.Integer({ + name: names.nonce || "TimeStampReq.nonce", + optional: true + }), new asn1js.Boolean({ + name: names.certReq || "TimeStampReq.certReq", + optional: true + }), new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: [new asn1js.Repeated({ + name: names.extensions || "TimeStampReq.extensions", + value: _Extension.default.schema() + })] + }) // IMPLICIT SEQUENCE value + ] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["TimeStampReq.version", "TimeStampReq.messageImprint", "TimeStampReq.reqPolicy", "TimeStampReq.nonce", "TimeStampReq.certReq", "TimeStampReq.extensions"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, TimeStampReq.schema()); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for TimeStampReq"); //endregion + //region Get internal properties from parsed schema + + this.version = asn1.result["TimeStampReq.version"].valueBlock.valueDec; + this.messageImprint = new _MessageImprint.default({ + schema: asn1.result["TimeStampReq.messageImprint"] + }); + if ("TimeStampReq.reqPolicy" in asn1.result) this.reqPolicy = asn1.result["TimeStampReq.reqPolicy"].valueBlock.toString(); + if ("TimeStampReq.nonce" in asn1.result) this.nonce = asn1.result["TimeStampReq.nonce"]; + if ("TimeStampReq.certReq" in asn1.result) this.certReq = asn1.result["TimeStampReq.certReq"].valueBlock.value; + if ("TimeStampReq.extensions" in asn1.result) this.extensions = Array.from(asn1.result["TimeStampReq.extensions"], element => new _Extension.default({ + schema: element + })); //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Create array for output sequence + const outputArray = []; + outputArray.push(new asn1js.Integer({ + value: this.version + })); + outputArray.push(this.messageImprint.toSchema()); + if ("reqPolicy" in this) outputArray.push(new asn1js.ObjectIdentifier({ + value: this.reqPolicy + })); + if ("nonce" in this) outputArray.push(this.nonce); + if ("certReq" in this && TimeStampReq.compareWithDefault("certReq", this.certReq) === false) outputArray.push(new asn1js.Boolean({ + value: this.certReq + })); //region Create array of extensions + + if ("extensions" in this) { + outputArray.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, + // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + + }, + value: Array.from(this.extensions, element => element.toSchema()) + })); + } //endregion + //endregion + //region Construct and return new ASN.1 schema for this object + + + return new asn1js.Sequence({ + value: outputArray + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + const _object = { + version: this.version, + messageImprint: this.messageImprint.toJSON() + }; + if ("reqPolicy" in this) _object.reqPolicy = this.reqPolicy; + if ("nonce" in this) _object.nonce = this.nonce.toJSON(); + if ("certReq" in this && TimeStampReq.compareWithDefault("certReq", this.certReq) === false) _object.certReq = this.certReq; + if ("extensions" in this) _object.extensions = Array.from(this.extensions, element => element.toJSON()); + return _object; + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = TimeStampReq; + +},{"./Extension.js":38,"./MessageImprint.js":53,"asn1js":112,"pvutils":113}],109:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _PKIStatusInfo = _interopRequireDefault(require("./PKIStatusInfo.js")); + +var _ContentInfo = _interopRequireDefault(require("./ContentInfo.js")); + +var _SignedData = _interopRequireDefault(require("./SignedData.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** + +/** + * Class from RFC3161 + */ +class TimeStampResp { + //********************************************************************************** + + /** + * Constructor for TimeStampResp class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) { + //region Internal properties of the object + + /** + * @type {PKIStatusInfo} + * @desc status + */ + this.status = (0, _pvutils.getParametersValue)(parameters, "status", TimeStampResp.defaultValues("status")); + if ("timeStampToken" in parameters) + /** + * @type {ContentInfo} + * @desc timeStampToken + */ + this.timeStampToken = (0, _pvutils.getParametersValue)(parameters, "timeStampToken", TimeStampResp.defaultValues("timeStampToken")); //endregion + //region If input argument array contains "schema" for this object + + if ("schema" in parameters) this.fromSchema(parameters.schema); //endregion + } //********************************************************************************** + + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + + + static defaultValues(memberName) { + switch (memberName) { + case "status": + return new _PKIStatusInfo.default(); + + case "timeStampToken": + return new _ContentInfo.default(); + + default: + throw new Error(`Invalid member name for TimeStampResp class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + + + static compareWithDefault(memberName, memberValue) { + switch (memberName) { + case "status": + return _PKIStatusInfo.default.compareWithDefault("status", memberValue.status) && "statusStrings" in memberValue === false && "failInfo" in memberValue === false; + + case "timeStampToken": + return memberValue.contentType === "" && memberValue.content instanceof asn1js.Any; + + default: + throw new Error(`Invalid member name for TimeStampResp class: ${memberName}`); + } + } //********************************************************************************** + + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * TimeStampResp ::= SEQUENCE { + * status PKIStatusInfo, + * timeStampToken TimeStampToken OPTIONAL } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + + + static schema(parameters = {}) { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [status] + * @property {string} [timeStampToken] + */ + const names = (0, _pvutils.getParametersValue)(parameters, "names", {}); + return new asn1js.Sequence({ + name: names.blockName || "TimeStampResp", + value: [_PKIStatusInfo.default.schema(names.status || { + names: { + blockName: "TimeStampResp.status" + } + }), _ContentInfo.default.schema(names.timeStampToken || { + names: { + blockName: "TimeStampResp.timeStampToken", + optional: true + } + })] + }); + } //********************************************************************************** + + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + + + fromSchema(schema) { + //region Clear input data first + (0, _pvutils.clearProps)(schema, ["TimeStampResp.status", "TimeStampResp.timeStampToken"]); //endregion + //region Check the schema is valid + + const asn1 = asn1js.compareSchema(schema, schema, TimeStampResp.schema()); + if (asn1.verified === false) throw new Error("Object's schema was not verified against input data for TimeStampResp"); //endregion + //region Get internal properties from parsed schema + + this.status = new _PKIStatusInfo.default({ + schema: asn1.result["TimeStampResp.status"] + }); + if ("TimeStampResp.timeStampToken" in asn1.result) this.timeStampToken = new _ContentInfo.default({ + schema: asn1.result["TimeStampResp.timeStampToken"] + }); //endregion + } //********************************************************************************** + + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + + + toSchema() { + //region Create array for output sequence + const outputArray = []; + outputArray.push(this.status.toSchema()); + if ("timeStampToken" in this) outputArray.push(this.timeStampToken.toSchema()); //endregion + //region Construct and return new ASN.1 schema for this object + + return new asn1js.Sequence({ + value: outputArray + }); //endregion + } //********************************************************************************** + + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + + + toJSON() { + const _object = { + status: this.status + }; + if ("timeStampToken" in this) _object.timeStampToken = this.timeStampToken.toJSON(); + return _object; + } //********************************************************************************** + + /** + * Sign current TSP Response + * @param {Object} privateKey Private key for "subjectPublicKeyInfo" structure + * @param {string} [hashAlgorithm] Hashing algorithm. Default SHA-1 + * @returns {Promise} + */ + + + sign(privateKey, hashAlgorithm) { + //region Check that "timeStampToken" exists + if ("timeStampToken" in this === false) return Promise.reject("timeStampToken is absent in TSP response"); //endregion + //region Check that "timeStampToken" has a right internal format + + if (this.timeStampToken.contentType !== "1.2.840.113549.1.7.2") // Must be a CMS signed data + return Promise.reject(`Wrong format of timeStampToken: ${this.timeStampToken.contentType}`); //endregion + //region Sign internal signed data value + + const signed = new _ContentInfo.default({ + schema: this.timeStampToken.content + }); + return signed.sign(privateKey, 0, hashAlgorithm); //endregion + } //********************************************************************************** + + /** + * Verify current TSP Response + * @param {Object} verificationParameters Input parameters for verification + * @returns {Promise} + */ + + + verify(verificationParameters = { + signer: 0, + trustedCerts: [], + data: new ArrayBuffer(0) + }) { + //region Check that "timeStampToken" exists + if ("timeStampToken" in this === false) return Promise.reject("timeStampToken is absent in TSP response"); //endregion + //region Check that "timeStampToken" has a right internal format + + if (this.timeStampToken.contentType !== "1.2.840.113549.1.7.2") // Must be a CMS signed data + return Promise.reject(`Wrong format of timeStampToken: ${this.timeStampToken.contentType}`); //endregion + //region Verify internal signed data value + + const signed = new _SignedData.default({ + schema: this.timeStampToken.content + }); + return signed.verify(verificationParameters); //endregion + } //********************************************************************************** + + +} //************************************************************************************** + + +exports.default = TimeStampResp; + +},{"./ContentInfo.js":26,"./PKIStatusInfo.js":69,"./SignedData.js":101,"asn1js":112,"pvutils":113}],110:[function(require,module,exports){ +(function (process,global){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.setEngine = setEngine; +exports.getEngine = getEngine; +exports.getCrypto = getCrypto; +exports.getRandomValues = getRandomValues; +exports.getOIDByAlgorithm = getOIDByAlgorithm; +exports.getAlgorithmParameters = getAlgorithmParameters; +exports.createCMSECDSASignature = createCMSECDSASignature; +exports.stringPrep = stringPrep; +exports.createECDSASignatureFromCMS = createECDSASignatureFromCMS; +exports.getAlgorithmByOID = getAlgorithmByOID; +exports.getHashAlgorithm = getHashAlgorithm; +exports.kdfWithCounter = kdfWithCounter; +exports.kdf = kdf; + +var asn1js = _interopRequireWildcard(require("asn1js")); + +var _pvutils = require("pvutils"); + +var _CryptoEngine = _interopRequireDefault(require("./CryptoEngine.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +//************************************************************************************** +//region Crypto engine related function +//************************************************************************************** +let engine = { + name: "none", + crypto: null, + subtle: null +}; //************************************************************************************** + +function setEngine(name, crypto, subtle) { + //region We are in Node + // noinspection JSUnresolvedVariable + if (typeof process !== "undefined" && "pid" in process && typeof global !== "undefined" && typeof window === "undefined") { + // noinspection ES6ModulesDependencies, JSUnresolvedVariable + if (typeof global[process.pid] === "undefined") { + // noinspection JSUnresolvedVariable + global[process.pid] = {}; + } else { + // noinspection JSUnresolvedVariable + if (typeof global[process.pid] !== "object") { + // noinspection JSUnresolvedVariable + throw new Error(`Name global.${process.pid} already exists and it is not an object`); + } + } // noinspection JSUnresolvedVariable + + + if (typeof global[process.pid].pkijs === "undefined") { + // noinspection JSUnresolvedVariable + global[process.pid].pkijs = {}; + } else { + // noinspection JSUnresolvedVariable + if (typeof global[process.pid].pkijs !== "object") { + // noinspection JSUnresolvedVariable + throw new Error(`Name global.${process.pid}.pkijs already exists and it is not an object`); + } + } // noinspection JSUnresolvedVariable + + + global[process.pid].pkijs.engine = { + name: name, + crypto: crypto, + subtle: subtle + }; + } //endregion + //region We are in browser + else { + engine = { + name: name, + crypto: crypto, + subtle: subtle + }; + } //endregion + +} //************************************************************************************** + + +function getEngine() { + //region We are in Node + // noinspection JSUnresolvedVariable + if (typeof process !== "undefined" && "pid" in process && typeof global !== "undefined" && typeof window === "undefined") { + let _engine; + + try { + // noinspection JSUnresolvedVariable + _engine = global[process.pid].pkijs.engine; + } catch (ex) { + throw new Error("Please call \"setEngine\" before call to \"getEngine\""); + } + + return _engine; + } //endregion + + + return engine; +} //************************************************************************************** + + +(function initCryptoEngine() { + if (typeof self !== "undefined") { + if ("crypto" in self) { + let engineName = "webcrypto"; + /** + * Standard crypto object + * @type {Object} + * @property {Object} [webkitSubtle] Subtle object from Apple + */ + + const cryptoObject = self.crypto; + let subtleObject; // Apple Safari support + + if ("webkitSubtle" in self.crypto) { + try { + subtleObject = self.crypto.webkitSubtle; + } catch (ex) { + subtleObject = self.crypto.subtle; + } + + engineName = "safari"; + } + + if ("subtle" in self.crypto) subtleObject = self.crypto.subtle; + + if (typeof subtleObject === "undefined") { + engine = { + name: engineName, + crypto: cryptoObject, + subtle: null + }; + } else { + engine = { + name: engineName, + crypto: cryptoObject, + subtle: new _CryptoEngine.default({ + name: engineName, + crypto: self.crypto, + subtle: subtleObject + }) + }; + } + } + } + + setEngine(engine.name, engine.crypto, engine.subtle); +})(); //************************************************************************************** +//endregion +//************************************************************************************** +//region Declaration of common functions +//************************************************************************************** + +/** + * Get crypto subtle from current "crypto engine" or "undefined" + * @returns {({decrypt, deriveKey, digest, encrypt, exportKey, generateKey, importKey, sign, unwrapKey, verify, wrapKey}|null)} + */ + + +function getCrypto() { + const _engine = getEngine(); + + if (_engine.subtle !== null) return _engine.subtle; + return undefined; +} //************************************************************************************** + +/** + * Initialize input Uint8Array by random values (with help from current "crypto engine") + * @param {!Uint8Array} view + * @returns {*} + */ + + +function getRandomValues(view) { + return getEngine().subtle.getRandomValues(view); +} //************************************************************************************** + +/** + * Get OID for each specific algorithm + * @param {Object} algorithm + * @returns {string} + */ + + +function getOIDByAlgorithm(algorithm) { + return getEngine().subtle.getOIDByAlgorithm(algorithm); +} //************************************************************************************** + +/** + * Get default algorithm parameters for each kind of operation + * @param {string} algorithmName Algorithm name to get common parameters for + * @param {string} operation Kind of operation: "sign", "encrypt", "generatekey", "importkey", "exportkey", "verify" + * @returns {*} + */ + + +function getAlgorithmParameters(algorithmName, operation) { + return getEngine().subtle.getAlgorithmParameters(algorithmName, operation); +} //************************************************************************************** + +/** + * Create CMS ECDSA signature from WebCrypto ECDSA signature + * @param {ArrayBuffer} signatureBuffer WebCrypto result of "sign" function + * @returns {ArrayBuffer} + */ + + +function createCMSECDSASignature(signatureBuffer) { + //region Initial check for correct length + if (signatureBuffer.byteLength % 2 !== 0) return new ArrayBuffer(0); //endregion + //region Initial variables + + const length = signatureBuffer.byteLength / 2; // There are two equal parts inside incoming ArrayBuffer + + const rBuffer = new ArrayBuffer(length); + const rView = new Uint8Array(rBuffer); + rView.set(new Uint8Array(signatureBuffer, 0, length)); + const rInteger = new asn1js.Integer({ + valueHex: rBuffer + }); + const sBuffer = new ArrayBuffer(length); + const sView = new Uint8Array(sBuffer); + sView.set(new Uint8Array(signatureBuffer, length, length)); + const sInteger = new asn1js.Integer({ + valueHex: sBuffer + }); //endregion + + return new asn1js.Sequence({ + value: [rInteger.convertToDER(), sInteger.convertToDER()] + }).toBER(false); +} //************************************************************************************** + +/** + * String preparation function. In a future here will be realization of algorithm from RFC4518 + * @param {string} inputString JavaScript string. As soon as for each ASN.1 string type we have a specific transformation function here we will work with pure JavaScript string + * @returns {string} Formated string + */ + + +function stringPrep(inputString) { + //region Initial variables + let isSpace = false; + let cuttedResult = ""; //endregion + + const result = inputString.trim(); // Trim input string + //region Change all sequence of SPACE down to SPACE char + + for (let i = 0; i < result.length; i++) { + if (result.charCodeAt(i) === 32) { + if (isSpace === false) isSpace = true; + } else { + if (isSpace) { + cuttedResult += " "; + isSpace = false; + } + + cuttedResult += result[i]; + } + } //endregion + + + return cuttedResult.toLowerCase(); +} //************************************************************************************** + +/** + * Create a single ArrayBuffer from CMS ECDSA signature + * @param {Sequence} cmsSignature ASN.1 SEQUENCE contains CMS ECDSA signature + * @returns {ArrayBuffer} + */ + + +function createECDSASignatureFromCMS(cmsSignature) { + //region Check input variables + if (cmsSignature instanceof asn1js.Sequence === false) return new ArrayBuffer(0); + if (cmsSignature.valueBlock.value.length !== 2) return new ArrayBuffer(0); + if (cmsSignature.valueBlock.value[0] instanceof asn1js.Integer === false) return new ArrayBuffer(0); + if (cmsSignature.valueBlock.value[1] instanceof asn1js.Integer === false) return new ArrayBuffer(0); //endregion + + const rValue = cmsSignature.valueBlock.value[0].convertFromDER(); + const sValue = cmsSignature.valueBlock.value[1].convertFromDER(); //region Check the lengths of two parts are equal + + switch (true) { + case rValue.valueBlock.valueHex.byteLength < sValue.valueBlock.valueHex.byteLength: + { + if (sValue.valueBlock.valueHex.byteLength - rValue.valueBlock.valueHex.byteLength !== 1) throw new Error("Incorrect DER integer decoding"); + const correctedLength = sValue.valueBlock.valueHex.byteLength; + const rValueView = new Uint8Array(rValue.valueBlock.valueHex); + const rValueBufferCorrected = new ArrayBuffer(correctedLength); + const rValueViewCorrected = new Uint8Array(rValueBufferCorrected); + rValueViewCorrected.set(rValueView, 1); + rValueViewCorrected[0] = 0x00; // In order to be sure we do not have any garbage here + + return (0, _pvutils.utilConcatBuf)(rValueBufferCorrected, sValue.valueBlock.valueHex); + } + + case rValue.valueBlock.valueHex.byteLength > sValue.valueBlock.valueHex.byteLength: + { + if (rValue.valueBlock.valueHex.byteLength - sValue.valueBlock.valueHex.byteLength !== 1) throw new Error("Incorrect DER integer decoding"); + const correctedLength = rValue.valueBlock.valueHex.byteLength; + const sValueView = new Uint8Array(sValue.valueBlock.valueHex); + const sValueBufferCorrected = new ArrayBuffer(correctedLength); + const sValueViewCorrected = new Uint8Array(sValueBufferCorrected); + sValueViewCorrected.set(sValueView, 1); + sValueViewCorrected[0] = 0x00; // In order to be sure we do not have any garbage here + + return (0, _pvutils.utilConcatBuf)(rValue.valueBlock.valueHex, sValueBufferCorrected); + } + + default: + { + //region In case we have equal length and the length is not even with 2 + if (rValue.valueBlock.valueHex.byteLength % 2) { + const correctedLength = rValue.valueBlock.valueHex.byteLength + 1; + const rValueView = new Uint8Array(rValue.valueBlock.valueHex); + const rValueBufferCorrected = new ArrayBuffer(correctedLength); + const rValueViewCorrected = new Uint8Array(rValueBufferCorrected); + rValueViewCorrected.set(rValueView, 1); + rValueViewCorrected[0] = 0x00; // In order to be sure we do not have any garbage here + + const sValueView = new Uint8Array(sValue.valueBlock.valueHex); + const sValueBufferCorrected = new ArrayBuffer(correctedLength); + const sValueViewCorrected = new Uint8Array(sValueBufferCorrected); + sValueViewCorrected.set(sValueView, 1); + sValueViewCorrected[0] = 0x00; // In order to be sure we do not have any garbage here + + return (0, _pvutils.utilConcatBuf)(rValueBufferCorrected, sValueBufferCorrected); + } //endregion + + } + } //endregion + + + return (0, _pvutils.utilConcatBuf)(rValue.valueBlock.valueHex, sValue.valueBlock.valueHex); +} //************************************************************************************** + +/** + * Get WebCrypto algorithm by wel-known OID + * @param {string} oid well-known OID to search for + * @returns {Object} + */ + + +function getAlgorithmByOID(oid) { + return getEngine().subtle.getAlgorithmByOID(oid); +} //************************************************************************************** + +/** + * Getting hash algorithm by signature algorithm + * @param {AlgorithmIdentifier} signatureAlgorithm Signature algorithm + * @returns {string} + */ + + +function getHashAlgorithm(signatureAlgorithm) { + return getEngine().subtle.getHashAlgorithm(signatureAlgorithm); +} //************************************************************************************** + +/** + * ANS X9.63 Key Derivation Function having a "Counter" as a parameter + * @param {string} hashFunction Used hash function + * @param {ArrayBuffer} Zbuffer ArrayBuffer containing ECDH shared secret to derive from + * @param {number} Counter + * @param {ArrayBuffer} SharedInfo Usually DER encoded "ECC_CMS_SharedInfo" structure + */ + + +function kdfWithCounter(hashFunction, Zbuffer, Counter, SharedInfo) { + //region Check of input parameters + switch (hashFunction.toUpperCase()) { + case "SHA-1": + case "SHA-256": + case "SHA-384": + case "SHA-512": + break; + + default: + return Promise.reject(`Unknown hash function: ${hashFunction}`); + } + + if (Zbuffer instanceof ArrayBuffer === false) return Promise.reject("Please set \"Zbuffer\" as \"ArrayBuffer\""); + if (Zbuffer.byteLength === 0) return Promise.reject("\"Zbuffer\" has zero length, error"); + if (SharedInfo instanceof ArrayBuffer === false) return Promise.reject("Please set \"SharedInfo\" as \"ArrayBuffer\""); + if (Counter > 255) return Promise.reject("Please set \"Counter\" variable to value less or equal to 255"); //endregion + //region Initial variables + + const counterBuffer = new ArrayBuffer(4); + const counterView = new Uint8Array(counterBuffer); + counterView[0] = 0x00; + counterView[1] = 0x00; + counterView[2] = 0x00; + counterView[3] = Counter; + let combinedBuffer = new ArrayBuffer(0); //endregion + //region Get a "crypto" extension + + const crypto = getCrypto(); + if (typeof crypto === "undefined") return Promise.reject("Unable to create WebCrypto object"); //endregion + //region Create a combined ArrayBuffer for digesting + + combinedBuffer = (0, _pvutils.utilConcatBuf)(combinedBuffer, Zbuffer); + combinedBuffer = (0, _pvutils.utilConcatBuf)(combinedBuffer, counterBuffer); + combinedBuffer = (0, _pvutils.utilConcatBuf)(combinedBuffer, SharedInfo); //endregion + //region Return digest of combined ArrayBuffer and information about current counter + + return crypto.digest({ + name: hashFunction + }, combinedBuffer).then(result => ({ + counter: Counter, + result + })); //endregion +} //************************************************************************************** + +/** + * ANS X9.63 Key Derivation Function + * @param {string} hashFunction Used hash function + * @param {ArrayBuffer} Zbuffer ArrayBuffer containing ECDH shared secret to derive from + * @param {number} keydatalen Length (!!! in BITS !!!) of used kew derivation function + * @param {ArrayBuffer} SharedInfo Usually DER encoded "ECC_CMS_SharedInfo" structure + */ + + +function kdf(hashFunction, Zbuffer, keydatalen, SharedInfo) { + //region Initial variables + let hashLength = 0; + let maxCounter = 1; + const kdfArray = []; //endregion + //region Check of input parameters + + switch (hashFunction.toUpperCase()) { + case "SHA-1": + hashLength = 160; // In bits + + break; + + case "SHA-256": + hashLength = 256; // In bits + + break; + + case "SHA-384": + hashLength = 384; // In bits + + break; + + case "SHA-512": + hashLength = 512; // In bits + + break; + + default: + return Promise.reject(`Unknown hash function: ${hashFunction}`); + } + + if (Zbuffer instanceof ArrayBuffer === false) return Promise.reject("Please set \"Zbuffer\" as \"ArrayBuffer\""); + if (Zbuffer.byteLength === 0) return Promise.reject("\"Zbuffer\" has zero length, error"); + if (SharedInfo instanceof ArrayBuffer === false) return Promise.reject("Please set \"SharedInfo\" as \"ArrayBuffer\""); //endregion + //region Calculated maximum value of "Counter" variable + + const quotient = keydatalen / hashLength; + + if (Math.floor(quotient) > 0) { + maxCounter = Math.floor(quotient); + if (quotient - maxCounter > 0) maxCounter++; + } //endregion + //region Create an array of "kdfWithCounter" + + + for (let i = 1; i <= maxCounter; i++) kdfArray.push(kdfWithCounter(hashFunction, Zbuffer, i, SharedInfo)); //endregion + //region Return combined digest with specified length + + + return Promise.all(kdfArray).then(incomingResult => { + //region Initial variables + let combinedBuffer = new ArrayBuffer(0); + let currentCounter = 1; + let found = true; //endregion + //region Combine all buffer together + + while (found) { + found = false; + var _iteratorNormalCompletion = true; + var _didIteratorError = false; + var _iteratorError = undefined; + + try { + for (var _iterator = incomingResult[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { + const result = _step.value; + + if (result.counter === currentCounter) { + combinedBuffer = (0, _pvutils.utilConcatBuf)(combinedBuffer, result.result); + found = true; + break; + } + } + } catch (err) { + _didIteratorError = true; + _iteratorError = err; + } finally { + try { + if (!_iteratorNormalCompletion && _iterator.return != null) { + _iterator.return(); + } + } finally { + if (_didIteratorError) { + throw _iteratorError; + } + } + } + + currentCounter++; + } //endregion + //region Create output buffer with specified length + + + keydatalen >>= 3; // Divide by 8 since "keydatalen" is in bits + + if (combinedBuffer.byteLength > keydatalen) { + const newBuffer = new ArrayBuffer(keydatalen); + const newView = new Uint8Array(newBuffer); + const combinedView = new Uint8Array(combinedBuffer); + + for (let i = 0; i < keydatalen; i++) newView[i] = combinedView[i]; + + return newBuffer; + } + + return combinedBuffer; // Since the situation when "combinedBuffer.byteLength < keydatalen" here we have only "combinedBuffer.byteLength === keydatalen" + //endregion + }); //endregion +} //************************************************************************************** +//endregion +//************************************************************************************** + +}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{"./CryptoEngine.js":27,"_process":114,"asn1js":112,"pvutils":113}],111:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +Object.defineProperty(exports, "setEngine", { + enumerable: true, + get: function get() { + return _common.setEngine; + } +}); +Object.defineProperty(exports, "getEngine", { + enumerable: true, + get: function get() { + return _common.getEngine; + } +}); +Object.defineProperty(exports, "getCrypto", { + enumerable: true, + get: function get() { + return _common.getCrypto; + } +}); +Object.defineProperty(exports, "getRandomValues", { + enumerable: true, + get: function get() { + return _common.getRandomValues; + } +}); +Object.defineProperty(exports, "getOIDByAlgorithm", { + enumerable: true, + get: function get() { + return _common.getOIDByAlgorithm; + } +}); +Object.defineProperty(exports, "getAlgorithmParameters", { + enumerable: true, + get: function get() { + return _common.getAlgorithmParameters; + } +}); +Object.defineProperty(exports, "createCMSECDSASignature", { + enumerable: true, + get: function get() { + return _common.createCMSECDSASignature; + } +}); +Object.defineProperty(exports, "stringPrep", { + enumerable: true, + get: function get() { + return _common.stringPrep; + } +}); +Object.defineProperty(exports, "createECDSASignatureFromCMS", { + enumerable: true, + get: function get() { + return _common.createECDSASignatureFromCMS; + } +}); +Object.defineProperty(exports, "getAlgorithmByOID", { + enumerable: true, + get: function get() { + return _common.getAlgorithmByOID; + } +}); +Object.defineProperty(exports, "getHashAlgorithm", { + enumerable: true, + get: function get() { + return _common.getHashAlgorithm; + } +}); +Object.defineProperty(exports, "kdfWithCounter", { + enumerable: true, + get: function get() { + return _common.kdfWithCounter; + } +}); +Object.defineProperty(exports, "kdf", { + enumerable: true, + get: function get() { + return _common.kdf; + } +}); +Object.defineProperty(exports, "AccessDescription", { + enumerable: true, + get: function get() { + return _AccessDescription.default; + } +}); +Object.defineProperty(exports, "Accuracy", { + enumerable: true, + get: function get() { + return _Accuracy.default; + } +}); +Object.defineProperty(exports, "AlgorithmIdentifier", { + enumerable: true, + get: function get() { + return _AlgorithmIdentifier.default; + } +}); +Object.defineProperty(exports, "AltName", { + enumerable: true, + get: function get() { + return _AltName.default; + } +}); +Object.defineProperty(exports, "Attribute", { + enumerable: true, + get: function get() { + return _Attribute.default; + } +}); +Object.defineProperty(exports, "AttributeTypeAndValue", { + enumerable: true, + get: function get() { + return _AttributeTypeAndValue.default; + } +}); +Object.defineProperty(exports, "AuthenticatedSafe", { + enumerable: true, + get: function get() { + return _AuthenticatedSafe.default; + } +}); +Object.defineProperty(exports, "AuthorityKeyIdentifier", { + enumerable: true, + get: function get() { + return _AuthorityKeyIdentifier.default; + } +}); +Object.defineProperty(exports, "BasicConstraints", { + enumerable: true, + get: function get() { + return _BasicConstraints.default; + } +}); +Object.defineProperty(exports, "BasicOCSPResponse", { + enumerable: true, + get: function get() { + return _BasicOCSPResponse.default; + } +}); +Object.defineProperty(exports, "CRLBag", { + enumerable: true, + get: function get() { + return _CRLBag.default; + } +}); +Object.defineProperty(exports, "CRLDistributionPoints", { + enumerable: true, + get: function get() { + return _CRLDistributionPoints.default; + } +}); +Object.defineProperty(exports, "CertBag", { + enumerable: true, + get: function get() { + return _CertBag.default; + } +}); +Object.defineProperty(exports, "CertID", { + enumerable: true, + get: function get() { + return _CertID.default; + } +}); +Object.defineProperty(exports, "Certificate", { + enumerable: true, + get: function get() { + return _Certificate.default; + } +}); +Object.defineProperty(exports, "CertificateChainValidationEngine", { + enumerable: true, + get: function get() { + return _CertificateChainValidationEngine.default; + } +}); +Object.defineProperty(exports, "CertificatePolicies", { + enumerable: true, + get: function get() { + return _CertificatePolicies.default; + } +}); +Object.defineProperty(exports, "CertificateRevocationList", { + enumerable: true, + get: function get() { + return _CertificateRevocationList.default; + } +}); +Object.defineProperty(exports, "CertificateSet", { + enumerable: true, + get: function get() { + return _CertificateSet.default; + } +}); +Object.defineProperty(exports, "CertificationRequest", { + enumerable: true, + get: function get() { + return _CertificationRequest.default; + } +}); +Object.defineProperty(exports, "ContentInfo", { + enumerable: true, + get: function get() { + return _ContentInfo.default; + } +}); +Object.defineProperty(exports, "CryptoEngine", { + enumerable: true, + get: function get() { + return _CryptoEngine.default; + } +}); +Object.defineProperty(exports, "DigestInfo", { + enumerable: true, + get: function get() { + return _DigestInfo.default; + } +}); +Object.defineProperty(exports, "DistributionPoint", { + enumerable: true, + get: function get() { + return _DistributionPoint.default; + } +}); +Object.defineProperty(exports, "ECCCMSSharedInfo", { + enumerable: true, + get: function get() { + return _ECCCMSSharedInfo.default; + } +}); +Object.defineProperty(exports, "ECPrivateKey", { + enumerable: true, + get: function get() { + return _ECPrivateKey.default; + } +}); +Object.defineProperty(exports, "ECPublicKey", { + enumerable: true, + get: function get() { + return _ECPublicKey.default; + } +}); +Object.defineProperty(exports, "EncapsulatedContentInfo", { + enumerable: true, + get: function get() { + return _EncapsulatedContentInfo.default; + } +}); +Object.defineProperty(exports, "EncryptedContentInfo", { + enumerable: true, + get: function get() { + return _EncryptedContentInfo.default; + } +}); +Object.defineProperty(exports, "EncryptedData", { + enumerable: true, + get: function get() { + return _EncryptedData.default; + } +}); +Object.defineProperty(exports, "EnvelopedData", { + enumerable: true, + get: function get() { + return _EnvelopedData.default; + } +}); +Object.defineProperty(exports, "ExtKeyUsage", { + enumerable: true, + get: function get() { + return _ExtKeyUsage.default; + } +}); +Object.defineProperty(exports, "Extension", { + enumerable: true, + get: function get() { + return _Extension.default; + } +}); +Object.defineProperty(exports, "Extensions", { + enumerable: true, + get: function get() { + return _Extensions.default; + } +}); +Object.defineProperty(exports, "GeneralName", { + enumerable: true, + get: function get() { + return _GeneralName.default; + } +}); +Object.defineProperty(exports, "GeneralNames", { + enumerable: true, + get: function get() { + return _GeneralNames.default; + } +}); +Object.defineProperty(exports, "GeneralSubtree", { + enumerable: true, + get: function get() { + return _GeneralSubtree.default; + } +}); +Object.defineProperty(exports, "InfoAccess", { + enumerable: true, + get: function get() { + return _InfoAccess.default; + } +}); +Object.defineProperty(exports, "IssuerAndSerialNumber", { + enumerable: true, + get: function get() { + return _IssuerAndSerialNumber.default; + } +}); +Object.defineProperty(exports, "IssuingDistributionPoint", { + enumerable: true, + get: function get() { + return _IssuingDistributionPoint.default; + } +}); +Object.defineProperty(exports, "KEKIdentifier", { + enumerable: true, + get: function get() { + return _KEKIdentifier.default; + } +}); +Object.defineProperty(exports, "KEKRecipientInfo", { + enumerable: true, + get: function get() { + return _KEKRecipientInfo.default; + } +}); +Object.defineProperty(exports, "KeyAgreeRecipientIdentifier", { + enumerable: true, + get: function get() { + return _KeyAgreeRecipientIdentifier.default; + } +}); +Object.defineProperty(exports, "KeyAgreeRecipientInfo", { + enumerable: true, + get: function get() { + return _KeyAgreeRecipientInfo.default; + } +}); +Object.defineProperty(exports, "KeyBag", { + enumerable: true, + get: function get() { + return _KeyBag.default; + } +}); +Object.defineProperty(exports, "KeyTransRecipientInfo", { + enumerable: true, + get: function get() { + return _KeyTransRecipientInfo.default; + } +}); +Object.defineProperty(exports, "MacData", { + enumerable: true, + get: function get() { + return _MacData.default; + } +}); +Object.defineProperty(exports, "MessageImprint", { + enumerable: true, + get: function get() { + return _MessageImprint.default; + } +}); +Object.defineProperty(exports, "NameConstraints", { + enumerable: true, + get: function get() { + return _NameConstraints.default; + } +}); +Object.defineProperty(exports, "OCSPRequest", { + enumerable: true, + get: function get() { + return _OCSPRequest.default; + } +}); +Object.defineProperty(exports, "OCSPResponse", { + enumerable: true, + get: function get() { + return _OCSPResponse.default; + } +}); +Object.defineProperty(exports, "OriginatorIdentifierOrKey", { + enumerable: true, + get: function get() { + return _OriginatorIdentifierOrKey.default; + } +}); +Object.defineProperty(exports, "OriginatorInfo", { + enumerable: true, + get: function get() { + return _OriginatorInfo.default; + } +}); +Object.defineProperty(exports, "OriginatorPublicKey", { + enumerable: true, + get: function get() { + return _OriginatorPublicKey.default; + } +}); +Object.defineProperty(exports, "OtherCertificateFormat", { + enumerable: true, + get: function get() { + return _OtherCertificateFormat.default; + } +}); +Object.defineProperty(exports, "OtherKeyAttribute", { + enumerable: true, + get: function get() { + return _OtherKeyAttribute.default; + } +}); +Object.defineProperty(exports, "OtherPrimeInfo", { + enumerable: true, + get: function get() { + return _OtherPrimeInfo.default; + } +}); +Object.defineProperty(exports, "OtherRecipientInfo", { + enumerable: true, + get: function get() { + return _OtherRecipientInfo.default; + } +}); +Object.defineProperty(exports, "OtherRevocationInfoFormat", { + enumerable: true, + get: function get() { + return _OtherRevocationInfoFormat.default; + } +}); +Object.defineProperty(exports, "PBES2Params", { + enumerable: true, + get: function get() { + return _PBES2Params.default; + } +}); +Object.defineProperty(exports, "PBKDF2Params", { + enumerable: true, + get: function get() { + return _PBKDF2Params.default; + } +}); +Object.defineProperty(exports, "PFX", { + enumerable: true, + get: function get() { + return _PFX.default; + } +}); +Object.defineProperty(exports, "PKCS8ShroudedKeyBag", { + enumerable: true, + get: function get() { + return _PKCS8ShroudedKeyBag.default; + } +}); +Object.defineProperty(exports, "PKIStatusInfo", { + enumerable: true, + get: function get() { + return _PKIStatusInfo.default; + } +}); +Object.defineProperty(exports, "PasswordRecipientinfo", { + enumerable: true, + get: function get() { + return _PasswordRecipientinfo.default; + } +}); +Object.defineProperty(exports, "PolicyConstraints", { + enumerable: true, + get: function get() { + return _PolicyConstraints.default; + } +}); +Object.defineProperty(exports, "PolicyInformation", { + enumerable: true, + get: function get() { + return _PolicyInformation.default; + } +}); +Object.defineProperty(exports, "PolicyMapping", { + enumerable: true, + get: function get() { + return _PolicyMapping.default; + } +}); +Object.defineProperty(exports, "PolicyMappings", { + enumerable: true, + get: function get() { + return _PolicyMappings.default; + } +}); +Object.defineProperty(exports, "PolicyQualifierInfo", { + enumerable: true, + get: function get() { + return _PolicyQualifierInfo.default; + } +}); +Object.defineProperty(exports, "PrivateKeyInfo", { + enumerable: true, + get: function get() { + return _PrivateKeyInfo.default; + } +}); +Object.defineProperty(exports, "PrivateKeyUsagePeriod", { + enumerable: true, + get: function get() { + return _PrivateKeyUsagePeriod.default; + } +}); +Object.defineProperty(exports, "PublicKeyInfo", { + enumerable: true, + get: function get() { + return _PublicKeyInfo.default; + } +}); +Object.defineProperty(exports, "RSAESOAEPParams", { + enumerable: true, + get: function get() { + return _RSAESOAEPParams.default; + } +}); +Object.defineProperty(exports, "RSAPrivateKey", { + enumerable: true, + get: function get() { + return _RSAPrivateKey.default; + } +}); +Object.defineProperty(exports, "RSAPublicKey", { + enumerable: true, + get: function get() { + return _RSAPublicKey.default; + } +}); +Object.defineProperty(exports, "RSASSAPSSParams", { + enumerable: true, + get: function get() { + return _RSASSAPSSParams.default; + } +}); +Object.defineProperty(exports, "RecipientEncryptedKey", { + enumerable: true, + get: function get() { + return _RecipientEncryptedKey.default; + } +}); +Object.defineProperty(exports, "RecipientEncryptedKeys", { + enumerable: true, + get: function get() { + return _RecipientEncryptedKeys.default; + } +}); +Object.defineProperty(exports, "RecipientIdentifier", { + enumerable: true, + get: function get() { + return _RecipientIdentifier.default; + } +}); +Object.defineProperty(exports, "RecipientInfo", { + enumerable: true, + get: function get() { + return _RecipientInfo.default; + } +}); +Object.defineProperty(exports, "RecipientKeyIdentifier", { + enumerable: true, + get: function get() { + return _RecipientKeyIdentifier.default; + } +}); +Object.defineProperty(exports, "RelativeDistinguishedNames", { + enumerable: true, + get: function get() { + return _RelativeDistinguishedNames.default; + } +}); +Object.defineProperty(exports, "Request", { + enumerable: true, + get: function get() { + return _Request.default; + } +}); +Object.defineProperty(exports, "ResponseBytes", { + enumerable: true, + get: function get() { + return _ResponseBytes.default; + } +}); +Object.defineProperty(exports, "ResponseData", { + enumerable: true, + get: function get() { + return _ResponseData.default; + } +}); +Object.defineProperty(exports, "RevocationInfoChoices", { + enumerable: true, + get: function get() { + return _RevocationInfoChoices.default; + } +}); +Object.defineProperty(exports, "RevokedCertificate", { + enumerable: true, + get: function get() { + return _RevokedCertificate.default; + } +}); +Object.defineProperty(exports, "SafeBag", { + enumerable: true, + get: function get() { + return _SafeBag.default; + } +}); +Object.defineProperty(exports, "SafeContents", { + enumerable: true, + get: function get() { + return _SafeContents.default; + } +}); +Object.defineProperty(exports, "SecretBag", { + enumerable: true, + get: function get() { + return _SecretBag.default; + } +}); +Object.defineProperty(exports, "Signature", { + enumerable: true, + get: function get() { + return _Signature.default; + } +}); +Object.defineProperty(exports, "SignedAndUnsignedAttributes", { + enumerable: true, + get: function get() { + return _SignedAndUnsignedAttributes.default; + } +}); +Object.defineProperty(exports, "SignedData", { + enumerable: true, + get: function get() { + return _SignedData.default; + } +}); +Object.defineProperty(exports, "SignerInfo", { + enumerable: true, + get: function get() { + return _SignerInfo.default; + } +}); +Object.defineProperty(exports, "SingleResponse", { + enumerable: true, + get: function get() { + return _SingleResponse.default; + } +}); +Object.defineProperty(exports, "SubjectDirectoryAttributes", { + enumerable: true, + get: function get() { + return _SubjectDirectoryAttributes.default; + } +}); +Object.defineProperty(exports, "TBSRequest", { + enumerable: true, + get: function get() { + return _TBSRequest.default; + } +}); +Object.defineProperty(exports, "TSTInfo", { + enumerable: true, + get: function get() { + return _TSTInfo.default; + } +}); +Object.defineProperty(exports, "Time", { + enumerable: true, + get: function get() { + return _Time.default; + } +}); +Object.defineProperty(exports, "TimeStampReq", { + enumerable: true, + get: function get() { + return _TimeStampReq.default; + } +}); +Object.defineProperty(exports, "TimeStampResp", { + enumerable: true, + get: function get() { + return _TimeStampResp.default; + } +}); +Object.defineProperty(exports, "SignedCertificateTimestampList", { + enumerable: true, + get: function get() { + return _SignedCertificateTimestampList.default; + } +}); +Object.defineProperty(exports, "SignedCertificateTimestamp", { + enumerable: true, + get: function get() { + return _SignedCertificateTimestampList.SignedCertificateTimestamp; + } +}); +Object.defineProperty(exports, "verifySCTsForCertificate", { + enumerable: true, + get: function get() { + return _SignedCertificateTimestampList.verifySCTsForCertificate; + } +}); +Object.defineProperty(exports, "CertificateTemplate", { + enumerable: true, + get: function get() { + return _CertificateTemplate.default; + } +}); +Object.defineProperty(exports, "CAVersion", { + enumerable: true, + get: function get() { + return _CAVersion.default; + } +}); +Object.defineProperty(exports, "QCStatements", { + enumerable: true, + get: function get() { + return _CAVersion.default; + } +}); +Object.defineProperty(exports, "QCStatement", { + enumerable: true, + get: function get() { + return _QCStatements.QCStatement; + } +}); + +var _common = require("./common.js"); + +var _AccessDescription = _interopRequireDefault(require("./AccessDescription.js")); + +var _Accuracy = _interopRequireDefault(require("./Accuracy.js")); + +var _AlgorithmIdentifier = _interopRequireDefault(require("./AlgorithmIdentifier.js")); + +var _AltName = _interopRequireDefault(require("./AltName.js")); + +var _Attribute = _interopRequireDefault(require("./Attribute.js")); + +var _AttributeTypeAndValue = _interopRequireDefault(require("./AttributeTypeAndValue.js")); + +var _AuthenticatedSafe = _interopRequireDefault(require("./AuthenticatedSafe.js")); + +var _AuthorityKeyIdentifier = _interopRequireDefault(require("./AuthorityKeyIdentifier.js")); + +var _BasicConstraints = _interopRequireDefault(require("./BasicConstraints.js")); + +var _BasicOCSPResponse = _interopRequireDefault(require("./BasicOCSPResponse.js")); + +var _CRLBag = _interopRequireDefault(require("./CRLBag.js")); + +var _CRLDistributionPoints = _interopRequireDefault(require("./CRLDistributionPoints.js")); + +var _CertBag = _interopRequireDefault(require("./CertBag.js")); + +var _CertID = _interopRequireDefault(require("./CertID.js")); + +var _Certificate = _interopRequireDefault(require("./Certificate.js")); + +var _CertificateChainValidationEngine = _interopRequireDefault(require("./CertificateChainValidationEngine.js")); + +var _CertificatePolicies = _interopRequireDefault(require("./CertificatePolicies.js")); + +var _CertificateRevocationList = _interopRequireDefault(require("./CertificateRevocationList.js")); + +var _CertificateSet = _interopRequireDefault(require("./CertificateSet.js")); + +var _CertificationRequest = _interopRequireDefault(require("./CertificationRequest.js")); + +var _ContentInfo = _interopRequireDefault(require("./ContentInfo.js")); + +var _CryptoEngine = _interopRequireDefault(require("./CryptoEngine.js")); + +var _DigestInfo = _interopRequireDefault(require("./DigestInfo.js")); + +var _DistributionPoint = _interopRequireDefault(require("./DistributionPoint.js")); + +var _ECCCMSSharedInfo = _interopRequireDefault(require("./ECCCMSSharedInfo.js")); + +var _ECPrivateKey = _interopRequireDefault(require("./ECPrivateKey.js")); + +var _ECPublicKey = _interopRequireDefault(require("./ECPublicKey.js")); + +var _EncapsulatedContentInfo = _interopRequireDefault(require("./EncapsulatedContentInfo.js")); + +var _EncryptedContentInfo = _interopRequireDefault(require("./EncryptedContentInfo.js")); + +var _EncryptedData = _interopRequireDefault(require("./EncryptedData.js")); + +var _EnvelopedData = _interopRequireDefault(require("./EnvelopedData.js")); + +var _ExtKeyUsage = _interopRequireDefault(require("./ExtKeyUsage.js")); + +var _Extension = _interopRequireDefault(require("./Extension.js")); + +var _Extensions = _interopRequireDefault(require("./Extensions.js")); + +var _GeneralName = _interopRequireDefault(require("./GeneralName.js")); + +var _GeneralNames = _interopRequireDefault(require("./GeneralNames.js")); + +var _GeneralSubtree = _interopRequireDefault(require("./GeneralSubtree.js")); + +var _InfoAccess = _interopRequireDefault(require("./InfoAccess.js")); + +var _IssuerAndSerialNumber = _interopRequireDefault(require("./IssuerAndSerialNumber.js")); + +var _IssuingDistributionPoint = _interopRequireDefault(require("./IssuingDistributionPoint.js")); + +var _KEKIdentifier = _interopRequireDefault(require("./KEKIdentifier.js")); + +var _KEKRecipientInfo = _interopRequireDefault(require("./KEKRecipientInfo.js")); + +var _KeyAgreeRecipientIdentifier = _interopRequireDefault(require("./KeyAgreeRecipientIdentifier.js")); + +var _KeyAgreeRecipientInfo = _interopRequireDefault(require("./KeyAgreeRecipientInfo.js")); + +var _KeyBag = _interopRequireDefault(require("./KeyBag.js")); + +var _KeyTransRecipientInfo = _interopRequireDefault(require("./KeyTransRecipientInfo.js")); + +var _MacData = _interopRequireDefault(require("./MacData.js")); + +var _MessageImprint = _interopRequireDefault(require("./MessageImprint.js")); + +var _NameConstraints = _interopRequireDefault(require("./NameConstraints.js")); + +var _OCSPRequest = _interopRequireDefault(require("./OCSPRequest.js")); + +var _OCSPResponse = _interopRequireDefault(require("./OCSPResponse.js")); + +var _OriginatorIdentifierOrKey = _interopRequireDefault(require("./OriginatorIdentifierOrKey.js")); + +var _OriginatorInfo = _interopRequireDefault(require("./OriginatorInfo.js")); + +var _OriginatorPublicKey = _interopRequireDefault(require("./OriginatorPublicKey.js")); + +var _OtherCertificateFormat = _interopRequireDefault(require("./OtherCertificateFormat.js")); + +var _OtherKeyAttribute = _interopRequireDefault(require("./OtherKeyAttribute.js")); + +var _OtherPrimeInfo = _interopRequireDefault(require("./OtherPrimeInfo.js")); + +var _OtherRecipientInfo = _interopRequireDefault(require("./OtherRecipientInfo.js")); + +var _OtherRevocationInfoFormat = _interopRequireDefault(require("./OtherRevocationInfoFormat.js")); + +var _PBES2Params = _interopRequireDefault(require("./PBES2Params.js")); + +var _PBKDF2Params = _interopRequireDefault(require("./PBKDF2Params.js")); + +var _PFX = _interopRequireDefault(require("./PFX.js")); + +var _PKCS8ShroudedKeyBag = _interopRequireDefault(require("./PKCS8ShroudedKeyBag.js")); + +var _PKIStatusInfo = _interopRequireDefault(require("./PKIStatusInfo.js")); + +var _PasswordRecipientinfo = _interopRequireDefault(require("./PasswordRecipientinfo.js")); + +var _PolicyConstraints = _interopRequireDefault(require("./PolicyConstraints.js")); + +var _PolicyInformation = _interopRequireDefault(require("./PolicyInformation.js")); + +var _PolicyMapping = _interopRequireDefault(require("./PolicyMapping.js")); + +var _PolicyMappings = _interopRequireDefault(require("./PolicyMappings.js")); + +var _PolicyQualifierInfo = _interopRequireDefault(require("./PolicyQualifierInfo.js")); + +var _PrivateKeyInfo = _interopRequireDefault(require("./PrivateKeyInfo.js")); + +var _PrivateKeyUsagePeriod = _interopRequireDefault(require("./PrivateKeyUsagePeriod.js")); + +var _PublicKeyInfo = _interopRequireDefault(require("./PublicKeyInfo.js")); + +var _RSAESOAEPParams = _interopRequireDefault(require("./RSAESOAEPParams.js")); + +var _RSAPrivateKey = _interopRequireDefault(require("./RSAPrivateKey.js")); + +var _RSAPublicKey = _interopRequireDefault(require("./RSAPublicKey.js")); + +var _RSASSAPSSParams = _interopRequireDefault(require("./RSASSAPSSParams.js")); + +var _RecipientEncryptedKey = _interopRequireDefault(require("./RecipientEncryptedKey.js")); + +var _RecipientEncryptedKeys = _interopRequireDefault(require("./RecipientEncryptedKeys.js")); + +var _RecipientIdentifier = _interopRequireDefault(require("./RecipientIdentifier.js")); + +var _RecipientInfo = _interopRequireDefault(require("./RecipientInfo.js")); + +var _RecipientKeyIdentifier = _interopRequireDefault(require("./RecipientKeyIdentifier.js")); + +var _RelativeDistinguishedNames = _interopRequireDefault(require("./RelativeDistinguishedNames.js")); + +var _Request = _interopRequireDefault(require("./Request.js")); + +var _ResponseBytes = _interopRequireDefault(require("./ResponseBytes.js")); + +var _ResponseData = _interopRequireDefault(require("./ResponseData.js")); + +var _RevocationInfoChoices = _interopRequireDefault(require("./RevocationInfoChoices.js")); + +var _RevokedCertificate = _interopRequireDefault(require("./RevokedCertificate.js")); + +var _SafeBag = _interopRequireDefault(require("./SafeBag.js")); + +var _SafeContents = _interopRequireDefault(require("./SafeContents.js")); + +var _SecretBag = _interopRequireDefault(require("./SecretBag.js")); + +var _Signature = _interopRequireDefault(require("./Signature.js")); + +var _SignedAndUnsignedAttributes = _interopRequireDefault(require("./SignedAndUnsignedAttributes.js")); + +var _SignedData = _interopRequireDefault(require("./SignedData.js")); + +var _SignerInfo = _interopRequireDefault(require("./SignerInfo.js")); + +var _SingleResponse = _interopRequireDefault(require("./SingleResponse.js")); + +var _SubjectDirectoryAttributes = _interopRequireDefault(require("./SubjectDirectoryAttributes.js")); + +var _TBSRequest = _interopRequireDefault(require("./TBSRequest.js")); + +var _TSTInfo = _interopRequireDefault(require("./TSTInfo.js")); + +var _Time = _interopRequireDefault(require("./Time.js")); + +var _TimeStampReq = _interopRequireDefault(require("./TimeStampReq.js")); + +var _TimeStampResp = _interopRequireDefault(require("./TimeStampResp.js")); + +var _SignedCertificateTimestampList = _interopRequireWildcard(require("./SignedCertificateTimestampList.js")); + +var _CertificateTemplate = _interopRequireDefault(require("./CertificateTemplate.js")); + +var _CAVersion = _interopRequireDefault(require("./CAVersion.js")); + +var _QCStatements = require("./QCStatements.js"); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +},{"./AccessDescription.js":2,"./Accuracy.js":3,"./AlgorithmIdentifier.js":4,"./AltName.js":5,"./Attribute.js":6,"./AttributeTypeAndValue.js":9,"./AuthenticatedSafe.js":10,"./AuthorityKeyIdentifier.js":11,"./BasicConstraints.js":12,"./BasicOCSPResponse.js":13,"./CAVersion.js":14,"./CRLBag.js":15,"./CRLDistributionPoints.js":16,"./CertBag.js":17,"./CertID.js":18,"./Certificate.js":19,"./CertificateChainValidationEngine.js":20,"./CertificatePolicies.js":21,"./CertificateRevocationList.js":22,"./CertificateSet.js":23,"./CertificateTemplate.js":24,"./CertificationRequest.js":25,"./ContentInfo.js":26,"./CryptoEngine.js":27,"./DigestInfo.js":28,"./DistributionPoint.js":29,"./ECCCMSSharedInfo.js":30,"./ECPrivateKey.js":31,"./ECPublicKey.js":32,"./EncapsulatedContentInfo.js":33,"./EncryptedContentInfo.js":34,"./EncryptedData.js":35,"./EnvelopedData.js":36,"./ExtKeyUsage.js":37,"./Extension.js":38,"./Extensions.js":39,"./GeneralName.js":40,"./GeneralNames.js":41,"./GeneralSubtree.js":42,"./InfoAccess.js":43,"./IssuerAndSerialNumber.js":44,"./IssuingDistributionPoint.js":45,"./KEKIdentifier.js":46,"./KEKRecipientInfo.js":47,"./KeyAgreeRecipientIdentifier.js":48,"./KeyAgreeRecipientInfo.js":49,"./KeyBag.js":50,"./KeyTransRecipientInfo.js":51,"./MacData.js":52,"./MessageImprint.js":53,"./NameConstraints.js":54,"./OCSPRequest.js":55,"./OCSPResponse.js":56,"./OriginatorIdentifierOrKey.js":57,"./OriginatorInfo.js":58,"./OriginatorPublicKey.js":59,"./OtherCertificateFormat.js":60,"./OtherKeyAttribute.js":61,"./OtherPrimeInfo.js":62,"./OtherRecipientInfo.js":63,"./OtherRevocationInfoFormat.js":64,"./PBES2Params.js":65,"./PBKDF2Params.js":66,"./PFX.js":67,"./PKCS8ShroudedKeyBag.js":68,"./PKIStatusInfo.js":69,"./PasswordRecipientinfo.js":70,"./PolicyConstraints.js":71,"./PolicyInformation.js":72,"./PolicyMapping.js":73,"./PolicyMappings.js":74,"./PolicyQualifierInfo.js":75,"./PrivateKeyInfo.js":76,"./PrivateKeyUsagePeriod.js":77,"./PublicKeyInfo.js":78,"./QCStatements.js":79,"./RSAESOAEPParams.js":80,"./RSAPrivateKey.js":81,"./RSAPublicKey.js":82,"./RSASSAPSSParams.js":83,"./RecipientEncryptedKey.js":84,"./RecipientEncryptedKeys.js":85,"./RecipientIdentifier.js":86,"./RecipientInfo.js":87,"./RecipientKeyIdentifier.js":88,"./RelativeDistinguishedNames.js":89,"./Request.js":90,"./ResponseBytes.js":91,"./ResponseData.js":92,"./RevocationInfoChoices.js":93,"./RevokedCertificate.js":94,"./SafeBag.js":95,"./SafeContents.js":96,"./SecretBag.js":97,"./Signature.js":98,"./SignedAndUnsignedAttributes.js":99,"./SignedCertificateTimestampList.js":100,"./SignedData.js":101,"./SignerInfo.js":102,"./SingleResponse.js":103,"./SubjectDirectoryAttributes.js":104,"./TBSRequest.js":105,"./TSTInfo.js":106,"./Time.js":107,"./TimeStampReq.js":108,"./TimeStampResp.js":109,"./common.js":110}],112:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.RawData = exports.Repeated = exports.Any = exports.Choice = exports.TIME = exports.Duration = exports.DateTime = exports.TimeOfDay = exports.DATE = exports.GeneralizedTime = exports.UTCTime = exports.CharacterString = exports.GeneralString = exports.VisibleString = exports.GraphicString = exports.IA5String = exports.VideotexString = exports.TeletexString = exports.PrintableString = exports.NumericString = exports.UniversalString = exports.BmpString = exports.Utf8String = exports.ObjectIdentifier = exports.Enumerated = exports.Integer = exports.BitString = exports.OctetString = exports.Null = exports.Set = exports.Sequence = exports.Boolean = exports.EndOfContent = exports.Constructed = exports.Primitive = exports.BaseBlock = undefined; +exports.fromBER = fromBER; +exports.compareSchema = compareSchema; +exports.verifySchema = verifySchema; +exports.fromJSON = fromJSON; + +var _pvutils = require("pvutils"); + +//************************************************************************************** +//region Declaration of global variables +//************************************************************************************** +const powers2 = [new Uint8Array([1])]; /* eslint-disable indent */ +/* + * Copyright (c) 2016-2018, Peculiar Ventures + * All rights reserved. + * + * Author 2016-2018, Yury Strozhevsky . + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + */ +//************************************************************************************** + +const digitsString = "0123456789"; +//************************************************************************************** +//endregion +//************************************************************************************** +//region Declaration for "LocalBaseBlock" class +//************************************************************************************** +/** + * Class used as a base block for all remaining ASN.1 classes + * @typedef LocalBaseBlock + * @interface + * @property {number} blockLength + * @property {string} error + * @property {Array.} warnings + * @property {ArrayBuffer} valueBeforeDecode + */ +class LocalBaseBlock { + //********************************************************************************** + /** + * Constructor for "LocalBaseBlock" class + * @param {Object} [parameters={}] + * @property {ArrayBuffer} [valueBeforeDecode] + */ + constructor(parameters = {}) { + /** + * @type {number} blockLength + */ + this.blockLength = (0, _pvutils.getParametersValue)(parameters, "blockLength", 0); + /** + * @type {string} error + */ + this.error = (0, _pvutils.getParametersValue)(parameters, "error", ""); + /** + * @type {Array.} warnings + */ + this.warnings = (0, _pvutils.getParametersValue)(parameters, "warnings", []); + //noinspection JSCheckFunctionSignatures + /** + * @type {ArrayBuffer} valueBeforeDecode + */ + if ("valueBeforeDecode" in parameters) this.valueBeforeDecode = parameters.valueBeforeDecode.slice(0);else this.valueBeforeDecode = new ArrayBuffer(0); + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "baseBlock"; + } + //********************************************************************************** + /** + * Convertion for the block to JSON object + * @returns {{blockName: string, blockLength: number, error: string, warnings: Array., valueBeforeDecode: string}} + */ + toJSON() { + return { + blockName: this.constructor.blockName(), + blockLength: this.blockLength, + error: this.error, + warnings: this.warnings, + valueBeforeDecode: (0, _pvutils.bufferToHexCodes)(this.valueBeforeDecode, 0, this.valueBeforeDecode.byteLength) + }; + } + //********************************************************************************** +} +//************************************************************************************** +//endregion +//************************************************************************************** +//region Description for "LocalHexBlock" class +//************************************************************************************** +/** + * Class used as a base block for all remaining ASN.1 classes + * @extends LocalBaseBlock + * @typedef LocalHexBlock + * @property {number} blockLength + * @property {string} error + * @property {Array.} warnings + * @property {ArrayBuffer} valueBeforeDecode + * @property {boolean} isHexOnly + * @property {ArrayBuffer} valueHex + */ +//noinspection JSUnusedLocalSymbols +const LocalHexBlock = BaseClass => class LocalHexBlockMixin extends BaseClass { + //********************************************************************************** + //noinspection JSUnusedGlobalSymbols + /** + * Constructor for "LocalHexBlock" class + * @param {Object} [parameters={}] + * @property {ArrayBuffer} [valueHex] + */ + constructor(parameters = {}) { + super(parameters); + + /** + * @type {boolean} + */ + this.isHexOnly = (0, _pvutils.getParametersValue)(parameters, "isHexOnly", false); + /** + * @type {ArrayBuffer} + */ + if ("valueHex" in parameters) this.valueHex = parameters.valueHex.slice(0);else this.valueHex = new ArrayBuffer(0); + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "hexBlock"; + } + //********************************************************************************** + /** + * Base function for converting block from BER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {number} Offset after least decoded byte + */ + fromBER(inputBuffer, inputOffset, inputLength) { + //region Basic check for parameters + //noinspection JSCheckFunctionSignatures + if ((0, _pvutils.checkBufferParams)(this, inputBuffer, inputOffset, inputLength) === false) return -1; + //endregion + + //region Getting Uint8Array from ArrayBuffer + const intBuffer = new Uint8Array(inputBuffer, inputOffset, inputLength); + //endregion + + //region Initial checks + if (intBuffer.length === 0) { + this.warnings.push("Zero buffer length"); + return inputOffset; + } + //endregion + + //region Copy input buffer to internal buffer + this.valueHex = inputBuffer.slice(inputOffset, inputOffset + inputLength); + //endregion + + this.blockLength = inputLength; + + return inputOffset + inputLength; + } + //********************************************************************************** + /** + * Encoding of current ASN.1 block into ASN.1 encoded array (BER rules) + * @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes + * @returns {ArrayBuffer} + */ + toBER(sizeOnly = false) { + if (this.isHexOnly !== true) { + this.error = "Flag \"isHexOnly\" is not set, abort"; + return new ArrayBuffer(0); + } + + if (sizeOnly === true) return new ArrayBuffer(this.valueHex.byteLength); + + //noinspection JSCheckFunctionSignatures + return this.valueHex.slice(0); + } + //********************************************************************************** + /** + * Convertion for the block to JSON object + * @returns {Object} + */ + toJSON() { + let object = {}; + + //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object + try { + object = super.toJSON(); + } catch (ex) {} + //endregion + + object.blockName = this.constructor.blockName(); + object.isHexOnly = this.isHexOnly; + object.valueHex = (0, _pvutils.bufferToHexCodes)(this.valueHex, 0, this.valueHex.byteLength); + + return object; + } + //********************************************************************************** +}; +//************************************************************************************** +//endregion +//************************************************************************************** +//region Declaration of identification block class +//************************************************************************************** +class LocalIdentificationBlock extends LocalHexBlock(LocalBaseBlock) { + //********************************************************************************** + /** + * Constructor for "LocalBaseBlock" class + * @param {Object} [parameters={}] + * @property {Object} [idBlock] + */ + constructor(parameters = {}) { + super(); + + if ("idBlock" in parameters) { + //region Properties from hexBlock class + this.isHexOnly = (0, _pvutils.getParametersValue)(parameters.idBlock, "isHexOnly", false); + this.valueHex = (0, _pvutils.getParametersValue)(parameters.idBlock, "valueHex", new ArrayBuffer(0)); + //endregion + + this.tagClass = (0, _pvutils.getParametersValue)(parameters.idBlock, "tagClass", -1); + this.tagNumber = (0, _pvutils.getParametersValue)(parameters.idBlock, "tagNumber", -1); + this.isConstructed = (0, _pvutils.getParametersValue)(parameters.idBlock, "isConstructed", false); + } else { + this.tagClass = -1; + this.tagNumber = -1; + this.isConstructed = false; + } + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "identificationBlock"; + } + //********************************************************************************** + /** + * Encoding of current ASN.1 block into ASN.1 encoded array (BER rules) + * @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes + * @returns {ArrayBuffer} + */ + toBER(sizeOnly = false) { + //region Initial variables + let firstOctet = 0; + let retBuf; + let retView; + //endregion + + switch (this.tagClass) { + case 1: + firstOctet |= 0x00; // UNIVERSAL + break; + case 2: + firstOctet |= 0x40; // APPLICATION + break; + case 3: + firstOctet |= 0x80; // CONTEXT-SPECIFIC + break; + case 4: + firstOctet |= 0xC0; // PRIVATE + break; + default: + this.error = "Unknown tag class"; + return new ArrayBuffer(0); + } + + if (this.isConstructed) firstOctet |= 0x20; + + if (this.tagNumber < 31 && !this.isHexOnly) { + retBuf = new ArrayBuffer(1); + retView = new Uint8Array(retBuf); + + if (!sizeOnly) { + let number = this.tagNumber; + number &= 0x1F; + firstOctet |= number; + + retView[0] = firstOctet; + } + + return retBuf; + } + + if (this.isHexOnly === false) { + const encodedBuf = (0, _pvutils.utilToBase)(this.tagNumber, 7); + const encodedView = new Uint8Array(encodedBuf); + const size = encodedBuf.byteLength; + + retBuf = new ArrayBuffer(size + 1); + retView = new Uint8Array(retBuf); + retView[0] = firstOctet | 0x1F; + + if (!sizeOnly) { + for (let i = 0; i < size - 1; i++) retView[i + 1] = encodedView[i] | 0x80; + + retView[size] = encodedView[size - 1]; + } + + return retBuf; + } + + retBuf = new ArrayBuffer(this.valueHex.byteLength + 1); + retView = new Uint8Array(retBuf); + + retView[0] = firstOctet | 0x1F; + + if (sizeOnly === false) { + const curView = new Uint8Array(this.valueHex); + + for (let i = 0; i < curView.length - 1; i++) retView[i + 1] = curView[i] | 0x80; + + retView[this.valueHex.byteLength] = curView[curView.length - 1]; + } + + return retBuf; + } + //********************************************************************************** + /** + * Base function for converting block from BER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {number} + */ + fromBER(inputBuffer, inputOffset, inputLength) { + //region Basic check for parameters + //noinspection JSCheckFunctionSignatures + if ((0, _pvutils.checkBufferParams)(this, inputBuffer, inputOffset, inputLength) === false) return -1; + //endregion + + //region Getting Uint8Array from ArrayBuffer + const intBuffer = new Uint8Array(inputBuffer, inputOffset, inputLength); + //endregion + + //region Initial checks + if (intBuffer.length === 0) { + this.error = "Zero buffer length"; + return -1; + } + //endregion + + //region Find tag class + const tagClassMask = intBuffer[0] & 0xC0; + + switch (tagClassMask) { + case 0x00: + this.tagClass = 1; // UNIVERSAL + break; + case 0x40: + this.tagClass = 2; // APPLICATION + break; + case 0x80: + this.tagClass = 3; // CONTEXT-SPECIFIC + break; + case 0xC0: + this.tagClass = 4; // PRIVATE + break; + default: + this.error = "Unknown tag class"; + return -1; + } + //endregion + + //region Find it's constructed or not + this.isConstructed = (intBuffer[0] & 0x20) === 0x20; + //endregion + + //region Find tag number + this.isHexOnly = false; + + const tagNumberMask = intBuffer[0] & 0x1F; + + //region Simple case (tag number < 31) + if (tagNumberMask !== 0x1F) { + this.tagNumber = tagNumberMask; + this.blockLength = 1; + } + //endregion + //region Tag number bigger or equal to 31 + else { + let count = 1; + + this.valueHex = new ArrayBuffer(255); + let tagNumberBufferMaxLength = 255; + let intTagNumberBuffer = new Uint8Array(this.valueHex); + + //noinspection JSBitwiseOperatorUsage + while (intBuffer[count] & 0x80) { + intTagNumberBuffer[count - 1] = intBuffer[count] & 0x7F; + count++; + + if (count >= intBuffer.length) { + this.error = "End of input reached before message was fully decoded"; + return -1; + } + + //region In case if tag number length is greater than 255 bytes (rare but possible case) + if (count === tagNumberBufferMaxLength) { + tagNumberBufferMaxLength += 255; + + const tempBuffer = new ArrayBuffer(tagNumberBufferMaxLength); + const tempBufferView = new Uint8Array(tempBuffer); + + for (let i = 0; i < intTagNumberBuffer.length; i++) tempBufferView[i] = intTagNumberBuffer[i]; + + this.valueHex = new ArrayBuffer(tagNumberBufferMaxLength); + intTagNumberBuffer = new Uint8Array(this.valueHex); + } + //endregion + } + + this.blockLength = count + 1; + intTagNumberBuffer[count - 1] = intBuffer[count] & 0x7F; // Write last byte to buffer + + //region Cut buffer + const tempBuffer = new ArrayBuffer(count); + const tempBufferView = new Uint8Array(tempBuffer); + + for (let i = 0; i < count; i++) tempBufferView[i] = intTagNumberBuffer[i]; + + this.valueHex = new ArrayBuffer(count); + intTagNumberBuffer = new Uint8Array(this.valueHex); + intTagNumberBuffer.set(tempBufferView); + //endregion + + //region Try to convert long tag number to short form + if (this.blockLength <= 9) this.tagNumber = (0, _pvutils.utilFromBase)(intTagNumberBuffer, 7);else { + this.isHexOnly = true; + this.warnings.push("Tag too long, represented as hex-coded"); + } + //endregion + } + //endregion + //endregion + + //region Check if constructed encoding was using for primitive type + if (this.tagClass === 1 && this.isConstructed) { + switch (this.tagNumber) { + case 1: // Boolean + case 2: // REAL + case 5: // Null + case 6: // OBJECT IDENTIFIER + case 9: // REAL + case 14: // Time + case 23: + case 24: + case 31: + case 32: + case 33: + case 34: + this.error = "Constructed encoding used for primitive type"; + return -1; + default: + } + } + //endregion + + return inputOffset + this.blockLength; // Return current offset in input buffer + } + //********************************************************************************** + /** + * Convertion for the block to JSON object + * @returns {{blockName: string, + * tagClass: number, + * tagNumber: number, + * isConstructed: boolean, + * isHexOnly: boolean, + * valueHex: ArrayBuffer, + * blockLength: number, + * error: string, warnings: Array., + * valueBeforeDecode: string}} + */ + toJSON() { + let object = {}; + + //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object + try { + object = super.toJSON(); + } catch (ex) {} + //endregion + + object.blockName = this.constructor.blockName(); + object.tagClass = this.tagClass; + object.tagNumber = this.tagNumber; + object.isConstructed = this.isConstructed; + + return object; + } + //********************************************************************************** +} +//************************************************************************************** +//endregion +//************************************************************************************** +//region Declaration of length block class +//************************************************************************************** +class LocalLengthBlock extends LocalBaseBlock { + //********************************************************************************** + /** + * Constructor for "LocalLengthBlock" class + * @param {Object} [parameters={}] + * @property {Object} [lenBlock] + */ + constructor(parameters = {}) { + super(); + + if ("lenBlock" in parameters) { + this.isIndefiniteForm = (0, _pvutils.getParametersValue)(parameters.lenBlock, "isIndefiniteForm", false); + this.longFormUsed = (0, _pvutils.getParametersValue)(parameters.lenBlock, "longFormUsed", false); + this.length = (0, _pvutils.getParametersValue)(parameters.lenBlock, "length", 0); + } else { + this.isIndefiniteForm = false; + this.longFormUsed = false; + this.length = 0; + } + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "lengthBlock"; + } + //********************************************************************************** + /** + * Base function for converting block from BER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {number} + */ + fromBER(inputBuffer, inputOffset, inputLength) { + //region Basic check for parameters + //noinspection JSCheckFunctionSignatures + if ((0, _pvutils.checkBufferParams)(this, inputBuffer, inputOffset, inputLength) === false) return -1; + //endregion + + //region Getting Uint8Array from ArrayBuffer + const intBuffer = new Uint8Array(inputBuffer, inputOffset, inputLength); + //endregion + + //region Initial checks + if (intBuffer.length === 0) { + this.error = "Zero buffer length"; + return -1; + } + + if (intBuffer[0] === 0xFF) { + this.error = "Length block 0xFF is reserved by standard"; + return -1; + } + //endregion + + //region Check for length form type + this.isIndefiniteForm = intBuffer[0] === 0x80; + //endregion + + //region Stop working in case of indefinite length form + if (this.isIndefiniteForm === true) { + this.blockLength = 1; + return inputOffset + this.blockLength; + } + //endregion + + //region Check is long form of length encoding using + this.longFormUsed = !!(intBuffer[0] & 0x80); + //endregion + + //region Stop working in case of short form of length value + if (this.longFormUsed === false) { + this.length = intBuffer[0]; + this.blockLength = 1; + return inputOffset + this.blockLength; + } + //endregion + + //region Calculate length value in case of long form + const count = intBuffer[0] & 0x7F; + + if (count > 8) // Too big length value + { + this.error = "Too big integer"; + return -1; + } + + if (count + 1 > intBuffer.length) { + this.error = "End of input reached before message was fully decoded"; + return -1; + } + + const lengthBufferView = new Uint8Array(count); + + for (let i = 0; i < count; i++) lengthBufferView[i] = intBuffer[i + 1]; + + if (lengthBufferView[count - 1] === 0x00) this.warnings.push("Needlessly long encoded length"); + + this.length = (0, _pvutils.utilFromBase)(lengthBufferView, 8); + + if (this.longFormUsed && this.length <= 127) this.warnings.push("Unneccesary usage of long length form"); + + this.blockLength = count + 1; + //endregion + + return inputOffset + this.blockLength; // Return current offset in input buffer + } + //********************************************************************************** + /** + * Encoding of current ASN.1 block into ASN.1 encoded array (BER rules) + * @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes + * @returns {ArrayBuffer} + */ + toBER(sizeOnly = false) { + //region Initial variables + let retBuf; + let retView; + //endregion + + if (this.length > 127) this.longFormUsed = true; + + if (this.isIndefiniteForm) { + retBuf = new ArrayBuffer(1); + + if (sizeOnly === false) { + retView = new Uint8Array(retBuf); + retView[0] = 0x80; + } + + return retBuf; + } + + if (this.longFormUsed === true) { + const encodedBuf = (0, _pvutils.utilToBase)(this.length, 8); + + if (encodedBuf.byteLength > 127) { + this.error = "Too big length"; + return new ArrayBuffer(0); + } + + retBuf = new ArrayBuffer(encodedBuf.byteLength + 1); + + if (sizeOnly === true) return retBuf; + + const encodedView = new Uint8Array(encodedBuf); + retView = new Uint8Array(retBuf); + + retView[0] = encodedBuf.byteLength | 0x80; + + for (let i = 0; i < encodedBuf.byteLength; i++) retView[i + 1] = encodedView[i]; + + return retBuf; + } + + retBuf = new ArrayBuffer(1); + + if (sizeOnly === false) { + retView = new Uint8Array(retBuf); + + retView[0] = this.length; + } + + return retBuf; + } + //********************************************************************************** + /** + * Convertion for the block to JSON object + * @returns {{blockName, blockLength, error, warnings, valueBeforeDecode}|{blockName: string, blockLength: number, error: string, warnings: Array., valueBeforeDecode: string}} + */ + toJSON() { + let object = {}; + + //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object + try { + object = super.toJSON(); + } catch (ex) {} + //endregion + + object.blockName = this.constructor.blockName(); + object.isIndefiniteForm = this.isIndefiniteForm; + object.longFormUsed = this.longFormUsed; + object.length = this.length; + + return object; + } + //********************************************************************************** +} +//************************************************************************************** +//endregion +//************************************************************************************** +//region Declaration of value block class +//************************************************************************************** +class LocalValueBlock extends LocalBaseBlock { + //********************************************************************************** + /** + * Constructor for "LocalValueBlock" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) { + super(parameters); + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "valueBlock"; + } + //********************************************************************************** + //noinspection JSUnusedLocalSymbols,JSUnusedLocalSymbols,JSUnusedLocalSymbols + /** + * Base function for converting block from BER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {number} + */ + fromBER(inputBuffer, inputOffset, inputLength) { + //region Throw an exception for a function which needs to be specified in extended classes + throw TypeError("User need to make a specific function in a class which extends \"LocalValueBlock\""); + //endregion + } + //********************************************************************************** + //noinspection JSUnusedLocalSymbols + /** + * Encoding of current ASN.1 block into ASN.1 encoded array (BER rules) + * @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes + * @returns {ArrayBuffer} + */ + toBER(sizeOnly = false) { + //region Throw an exception for a function which needs to be specified in extended classes + throw TypeError("User need to make a specific function in a class which extends \"LocalValueBlock\""); + //endregion + } + //********************************************************************************** +} +//************************************************************************************** +//endregion +//************************************************************************************** +//region Declaration of basic ASN.1 block class +//************************************************************************************** +class BaseBlock extends LocalBaseBlock { + //********************************************************************************** + /** + * Constructor for "BaseBlock" class + * @param {Object} [parameters={}] + * @property {Object} [primitiveSchema] + * @property {string} [name] + * @property {boolean} [optional] + * @param valueBlockType Type of value block + */ + constructor(parameters = {}, valueBlockType = LocalValueBlock) { + super(parameters); + + if ("name" in parameters) this.name = parameters.name; + if ("optional" in parameters) this.optional = parameters.optional; + if ("primitiveSchema" in parameters) this.primitiveSchema = parameters.primitiveSchema; + + this.idBlock = new LocalIdentificationBlock(parameters); + this.lenBlock = new LocalLengthBlock(parameters); + this.valueBlock = new valueBlockType(parameters); + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "BaseBlock"; + } + //********************************************************************************** + /** + * Base function for converting block from BER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {number} + */ + fromBER(inputBuffer, inputOffset, inputLength) { + const resultOffset = this.valueBlock.fromBER(inputBuffer, inputOffset, this.lenBlock.isIndefiniteForm === true ? inputLength : this.lenBlock.length); + if (resultOffset === -1) { + this.error = this.valueBlock.error; + return resultOffset; + } + + if (this.idBlock.error.length === 0) this.blockLength += this.idBlock.blockLength; + + if (this.lenBlock.error.length === 0) this.blockLength += this.lenBlock.blockLength; + + if (this.valueBlock.error.length === 0) this.blockLength += this.valueBlock.blockLength; + + return resultOffset; + } + //********************************************************************************** + /** + * Encoding of current ASN.1 block into ASN.1 encoded array (BER rules) + * @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes + * @returns {ArrayBuffer} + */ + toBER(sizeOnly = false) { + let retBuf; + + const idBlockBuf = this.idBlock.toBER(sizeOnly); + const valueBlockSizeBuf = this.valueBlock.toBER(true); + + this.lenBlock.length = valueBlockSizeBuf.byteLength; + const lenBlockBuf = this.lenBlock.toBER(sizeOnly); + + retBuf = (0, _pvutils.utilConcatBuf)(idBlockBuf, lenBlockBuf); + + let valueBlockBuf; + + if (sizeOnly === false) valueBlockBuf = this.valueBlock.toBER(sizeOnly);else valueBlockBuf = new ArrayBuffer(this.lenBlock.length); + + retBuf = (0, _pvutils.utilConcatBuf)(retBuf, valueBlockBuf); + + if (this.lenBlock.isIndefiniteForm === true) { + const indefBuf = new ArrayBuffer(2); + + if (sizeOnly === false) { + const indefView = new Uint8Array(indefBuf); + + indefView[0] = 0x00; + indefView[1] = 0x00; + } + + retBuf = (0, _pvutils.utilConcatBuf)(retBuf, indefBuf); + } + + return retBuf; + } + //********************************************************************************** + /** + * Convertion for the block to JSON object + * @returns {{blockName, blockLength, error, warnings, valueBeforeDecode}|{blockName: string, blockLength: number, error: string, warnings: Array., valueBeforeDecode: string}} + */ + toJSON() { + let object = {}; + + //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object + try { + object = super.toJSON(); + } catch (ex) {} + //endregion + + object.idBlock = this.idBlock.toJSON(); + object.lenBlock = this.lenBlock.toJSON(); + object.valueBlock = this.valueBlock.toJSON(); + + if ("name" in this) object.name = this.name; + if ("optional" in this) object.optional = this.optional; + if ("primitiveSchema" in this) object.primitiveSchema = this.primitiveSchema.toJSON(); + + return object; + } + //********************************************************************************** +} +exports.BaseBlock = BaseBlock; //************************************************************************************** +//endregion +//************************************************************************************** +//region Declaration of basic block for all PRIMITIVE types +//************************************************************************************** + +class LocalPrimitiveValueBlock extends LocalValueBlock { + //********************************************************************************** + /** + * Constructor for "LocalPrimitiveValueBlock" class + * @param {Object} [parameters={}] + * @property {ArrayBuffer} [valueBeforeDecode] + */ + constructor(parameters = {}) { + super(parameters); + + //region Variables from "hexBlock" class + if ("valueHex" in parameters) this.valueHex = parameters.valueHex.slice(0);else this.valueHex = new ArrayBuffer(0); + + this.isHexOnly = (0, _pvutils.getParametersValue)(parameters, "isHexOnly", true); + //endregion + } + //********************************************************************************** + /** + * Base function for converting block from BER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {number} + */ + fromBER(inputBuffer, inputOffset, inputLength) { + //region Basic check for parameters + //noinspection JSCheckFunctionSignatures + if ((0, _pvutils.checkBufferParams)(this, inputBuffer, inputOffset, inputLength) === false) return -1; + //endregion + + //region Getting Uint8Array from ArrayBuffer + const intBuffer = new Uint8Array(inputBuffer, inputOffset, inputLength); + //endregion + + //region Initial checks + if (intBuffer.length === 0) { + this.warnings.push("Zero buffer length"); + return inputOffset; + } + //endregion + + //region Copy input buffer into internal buffer + this.valueHex = new ArrayBuffer(intBuffer.length); + const valueHexView = new Uint8Array(this.valueHex); + + for (let i = 0; i < intBuffer.length; i++) valueHexView[i] = intBuffer[i]; + //endregion + + this.blockLength = inputLength; + + return inputOffset + inputLength; + } + //********************************************************************************** + //noinspection JSUnusedLocalSymbols + /** + * Encoding of current ASN.1 block into ASN.1 encoded array (BER rules) + * @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes + * @returns {ArrayBuffer} + */ + toBER(sizeOnly = false) { + return this.valueHex.slice(0); + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "PrimitiveValueBlock"; + } + //********************************************************************************** + /** + * Convertion for the block to JSON object + * @returns {{blockName, blockLength, error, warnings, valueBeforeDecode}|{blockName: string, blockLength: number, error: string, warnings: Array., valueBeforeDecode: string}} + */ + toJSON() { + let object = {}; + + //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object + try { + object = super.toJSON(); + } catch (ex) {} + //endregion + + object.valueHex = (0, _pvutils.bufferToHexCodes)(this.valueHex, 0, this.valueHex.byteLength); + object.isHexOnly = this.isHexOnly; + + return object; + } + //********************************************************************************** +} +//************************************************************************************** +class Primitive extends BaseBlock { + //********************************************************************************** + /** + * Constructor for "Primitive" class + * @param {Object} [parameters={}] + * @property {ArrayBuffer} [valueHex] + */ + constructor(parameters = {}) { + super(parameters, LocalPrimitiveValueBlock); + + this.idBlock.isConstructed = false; + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "PRIMITIVE"; + } + //********************************************************************************** +} +exports.Primitive = Primitive; //************************************************************************************** +//endregion +//************************************************************************************** +//region Declaration of basic block for all CONSTRUCTED types +//************************************************************************************** + +class LocalConstructedValueBlock extends LocalValueBlock { + //********************************************************************************** + /** + * Constructor for "LocalConstructedValueBlock" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) { + super(parameters); + + this.value = (0, _pvutils.getParametersValue)(parameters, "value", []); + this.isIndefiniteForm = (0, _pvutils.getParametersValue)(parameters, "isIndefiniteForm", false); + } + //********************************************************************************** + /** + * Base function for converting block from BER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {number} + */ + fromBER(inputBuffer, inputOffset, inputLength) { + //region Store initial offset and length + const initialOffset = inputOffset; + const initialLength = inputLength; + //endregion + + //region Basic check for parameters + //noinspection JSCheckFunctionSignatures + if ((0, _pvutils.checkBufferParams)(this, inputBuffer, inputOffset, inputLength) === false) return -1; + //endregion + + //region Getting Uint8Array from ArrayBuffer + const intBuffer = new Uint8Array(inputBuffer, inputOffset, inputLength); + //endregion + + //region Initial checks + if (intBuffer.length === 0) { + this.warnings.push("Zero buffer length"); + return inputOffset; + } + //endregion + + //region Aux function + function checkLen(indefiniteLength, length) { + if (indefiniteLength === true) return 1; + + return length; + } + //endregion + + let currentOffset = inputOffset; + + while (checkLen(this.isIndefiniteForm, inputLength) > 0) { + const returnObject = LocalFromBER(inputBuffer, currentOffset, inputLength); + if (returnObject.offset === -1) { + this.error = returnObject.result.error; + this.warnings.concat(returnObject.result.warnings); + return -1; + } + + currentOffset = returnObject.offset; + + this.blockLength += returnObject.result.blockLength; + inputLength -= returnObject.result.blockLength; + + this.value.push(returnObject.result); + + if (this.isIndefiniteForm === true && returnObject.result.constructor.blockName() === EndOfContent.blockName()) break; + } + + if (this.isIndefiniteForm === true) { + if (this.value[this.value.length - 1].constructor.blockName() === EndOfContent.blockName()) this.value.pop();else this.warnings.push("No EndOfContent block encoded"); + } + + //region Copy "inputBuffer" to "valueBeforeDecode" + this.valueBeforeDecode = inputBuffer.slice(initialOffset, initialOffset + initialLength); + //endregion + + return currentOffset; + } + //********************************************************************************** + /** + * Encoding of current ASN.1 block into ASN.1 encoded array (BER rules) + * @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes + * @returns {ArrayBuffer} + */ + toBER(sizeOnly = false) { + let retBuf = new ArrayBuffer(0); + + for (let i = 0; i < this.value.length; i++) { + const valueBuf = this.value[i].toBER(sizeOnly); + retBuf = (0, _pvutils.utilConcatBuf)(retBuf, valueBuf); + } + + return retBuf; + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "ConstructedValueBlock"; + } + //********************************************************************************** + /** + * Convertion for the block to JSON object + * @returns {{blockName, blockLength, error, warnings, valueBeforeDecode}|{blockName: string, blockLength: number, error: string, warnings: Array., valueBeforeDecode: string}} + */ + toJSON() { + let object = {}; + + //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object + try { + object = super.toJSON(); + } catch (ex) {} + //endregion + + object.isIndefiniteForm = this.isIndefiniteForm; + object.value = []; + for (let i = 0; i < this.value.length; i++) object.value.push(this.value[i].toJSON()); + + return object; + } + //********************************************************************************** +} +//************************************************************************************** +class Constructed extends BaseBlock { + //********************************************************************************** + /** + * Constructor for "Constructed" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) { + super(parameters, LocalConstructedValueBlock); + + this.idBlock.isConstructed = true; + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "CONSTRUCTED"; + } + //********************************************************************************** + /** + * Base function for converting block from BER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {number} + */ + fromBER(inputBuffer, inputOffset, inputLength) { + this.valueBlock.isIndefiniteForm = this.lenBlock.isIndefiniteForm; + + const resultOffset = this.valueBlock.fromBER(inputBuffer, inputOffset, this.lenBlock.isIndefiniteForm === true ? inputLength : this.lenBlock.length); + if (resultOffset === -1) { + this.error = this.valueBlock.error; + return resultOffset; + } + + if (this.idBlock.error.length === 0) this.blockLength += this.idBlock.blockLength; + + if (this.lenBlock.error.length === 0) this.blockLength += this.lenBlock.blockLength; + + if (this.valueBlock.error.length === 0) this.blockLength += this.valueBlock.blockLength; + + return resultOffset; + } + //********************************************************************************** +} +exports.Constructed = Constructed; //************************************************************************************** +//endregion +//************************************************************************************** +//region Declaration of ASN.1 EndOfContent type class +//************************************************************************************** + +class LocalEndOfContentValueBlock extends LocalValueBlock { + //********************************************************************************** + /** + * Constructor for "LocalEndOfContentValueBlock" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) { + super(parameters); + } + //********************************************************************************** + //noinspection JSUnusedLocalSymbols,JSUnusedLocalSymbols + /** + * Base function for converting block from BER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {number} + */ + fromBER(inputBuffer, inputOffset, inputLength) { + //region There is no "value block" for EndOfContent type and we need to return the same offset + return inputOffset; + //endregion + } + //********************************************************************************** + //noinspection JSUnusedLocalSymbols + /** + * Encoding of current ASN.1 block into ASN.1 encoded array (BER rules) + * @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes + * @returns {ArrayBuffer} + */ + toBER(sizeOnly = false) { + return new ArrayBuffer(0); + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "EndOfContentValueBlock"; + } + //********************************************************************************** +} +//************************************************************************************** +class EndOfContent extends BaseBlock { + //********************************************************************************** + constructor(paramaters = {}) { + super(paramaters, LocalEndOfContentValueBlock); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 0; // EndOfContent + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "EndOfContent"; + } + //********************************************************************************** +} +exports.EndOfContent = EndOfContent; //************************************************************************************** +//endregion +//************************************************************************************** +//region Declaration of ASN.1 Boolean type class +//************************************************************************************** + +class LocalBooleanValueBlock extends LocalValueBlock { + //********************************************************************************** + /** + * Constructor for "LocalBooleanValueBlock" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) { + super(parameters); + + this.value = (0, _pvutils.getParametersValue)(parameters, "value", false); + this.isHexOnly = (0, _pvutils.getParametersValue)(parameters, "isHexOnly", false); + + if ("valueHex" in parameters) this.valueHex = parameters.valueHex.slice(0);else { + this.valueHex = new ArrayBuffer(1); + if (this.value === true) { + const view = new Uint8Array(this.valueHex); + view[0] = 0xFF; + } + } + } + //********************************************************************************** + /** + * Base function for converting block from BER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {number} Offset after least decoded byte + */ + fromBER(inputBuffer, inputOffset, inputLength) { + //region Basic check for parameters + //noinspection JSCheckFunctionSignatures + if ((0, _pvutils.checkBufferParams)(this, inputBuffer, inputOffset, inputLength) === false) return -1; + //endregion + + //region Getting Uint8Array from ArrayBuffer + const intBuffer = new Uint8Array(inputBuffer, inputOffset, inputLength); + //endregion + + if (inputLength > 1) this.warnings.push("Boolean value encoded in more then 1 octet"); + + this.isHexOnly = true; + + //region Copy input buffer to internal array + this.valueHex = new ArrayBuffer(intBuffer.length); + const view = new Uint8Array(this.valueHex); + + for (let i = 0; i < intBuffer.length; i++) view[i] = intBuffer[i]; + //endregion + + if (_pvutils.utilDecodeTC.call(this) !== 0) this.value = true;else this.value = false; + + this.blockLength = inputLength; + + return inputOffset + inputLength; + } + //********************************************************************************** + //noinspection JSUnusedLocalSymbols + /** + * Encoding of current ASN.1 block into ASN.1 encoded array (BER rules) + * @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes + * @returns {ArrayBuffer} + */ + toBER(sizeOnly = false) { + return this.valueHex; + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "BooleanValueBlock"; + } + //********************************************************************************** + /** + * Convertion for the block to JSON object + * @returns {{blockName, blockLength, error, warnings, valueBeforeDecode}|{blockName: string, blockLength: number, error: string, warnings: Array., valueBeforeDecode: string}} + */ + toJSON() { + let object = {}; + + //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object + try { + object = super.toJSON(); + } catch (ex) {} + //endregion + + object.value = this.value; + object.isHexOnly = this.isHexOnly; + object.valueHex = (0, _pvutils.bufferToHexCodes)(this.valueHex, 0, this.valueHex.byteLength); + + return object; + } + //********************************************************************************** +} +//************************************************************************************** +class Boolean extends BaseBlock { + //********************************************************************************** + /** + * Constructor for "Boolean" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) { + super(parameters, LocalBooleanValueBlock); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 1; // Boolean + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "Boolean"; + } + //********************************************************************************** +} +exports.Boolean = Boolean; //************************************************************************************** +//endregion +//************************************************************************************** +//region Declaration of ASN.1 Sequence and Set type classes +//************************************************************************************** + +class Sequence extends Constructed { + //********************************************************************************** + /** + * Constructor for "Sequence" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) { + super(parameters); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 16; // Sequence + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "Sequence"; + } + //********************************************************************************** +} +exports.Sequence = Sequence; //************************************************************************************** + +class Set extends Constructed { + //********************************************************************************** + /** + * Constructor for "Set" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) { + super(parameters); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 17; // Set + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "Set"; + } + //********************************************************************************** +} +exports.Set = Set; //************************************************************************************** +//endregion +//************************************************************************************** +//region Declaration of ASN.1 Null type class +//************************************************************************************** + +class Null extends BaseBlock { + //********************************************************************************** + /** + * Constructor for "Null" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) { + super(parameters, LocalBaseBlock); // We will not have a call to "Null value block" because of specified "fromBER" and "toBER" functions + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 5; // Null + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "Null"; + } + //********************************************************************************** + //noinspection JSUnusedLocalSymbols + /** + * Base function for converting block from BER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {number} Offset after least decoded byte + */ + fromBER(inputBuffer, inputOffset, inputLength) { + if (this.lenBlock.length > 0) this.warnings.push("Non-zero length of value block for Null type"); + + if (this.idBlock.error.length === 0) this.blockLength += this.idBlock.blockLength; + + if (this.lenBlock.error.length === 0) this.blockLength += this.lenBlock.blockLength; + + this.blockLength += inputLength; + + if (inputOffset + inputLength > inputBuffer.byteLength) { + this.error = "End of input reached before message was fully decoded (inconsistent offset and length values)"; + return -1; + } + + return inputOffset + inputLength; + } + //********************************************************************************** + /** + * Encoding of current ASN.1 block into ASN.1 encoded array (BER rules) + * @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes + * @returns {ArrayBuffer} + */ + toBER(sizeOnly = false) { + const retBuf = new ArrayBuffer(2); + + if (sizeOnly === true) return retBuf; + + const retView = new Uint8Array(retBuf); + retView[0] = 0x05; + retView[1] = 0x00; + + return retBuf; + } + //********************************************************************************** +} +exports.Null = Null; //************************************************************************************** +//endregion +//************************************************************************************** +//region Declaration of ASN.1 OctetString type class +//************************************************************************************** + +class LocalOctetStringValueBlock extends LocalHexBlock(LocalConstructedValueBlock) { + //********************************************************************************** + /** + * Constructor for "LocalOctetStringValueBlock" class + * @param {Object} [parameters={}] + * @property {ArrayBuffer} [valueHex] + */ + constructor(parameters = {}) { + super(parameters); + + this.isConstructed = (0, _pvutils.getParametersValue)(parameters, "isConstructed", false); + } + //********************************************************************************** + /** + * Base function for converting block from BER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {number} Offset after least decoded byte + */ + fromBER(inputBuffer, inputOffset, inputLength) { + let resultOffset = 0; + + if (this.isConstructed === true) { + this.isHexOnly = false; + + resultOffset = LocalConstructedValueBlock.prototype.fromBER.call(this, inputBuffer, inputOffset, inputLength); + if (resultOffset === -1) return resultOffset; + + for (let i = 0; i < this.value.length; i++) { + const currentBlockName = this.value[i].constructor.blockName(); + + if (currentBlockName === EndOfContent.blockName()) { + if (this.isIndefiniteForm === true) break;else { + this.error = "EndOfContent is unexpected, OCTET STRING may consists of OCTET STRINGs only"; + return -1; + } + } + + if (currentBlockName !== OctetString.blockName()) { + this.error = "OCTET STRING may consists of OCTET STRINGs only"; + return -1; + } + } + } else { + this.isHexOnly = true; + + resultOffset = super.fromBER(inputBuffer, inputOffset, inputLength); + this.blockLength = inputLength; + } + + return resultOffset; + } + //********************************************************************************** + /** + * Encoding of current ASN.1 block into ASN.1 encoded array (BER rules) + * @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes + * @returns {ArrayBuffer} + */ + toBER(sizeOnly = false) { + if (this.isConstructed === true) return LocalConstructedValueBlock.prototype.toBER.call(this, sizeOnly); + + let retBuf = new ArrayBuffer(this.valueHex.byteLength); + + if (sizeOnly === true) return retBuf; + + if (this.valueHex.byteLength === 0) return retBuf; + + retBuf = this.valueHex.slice(0); + + return retBuf; + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "OctetStringValueBlock"; + } + //********************************************************************************** + toJSON() { + let object = {}; + + //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object + try { + object = super.toJSON(); + } catch (ex) {} + //endregion + + object.isConstructed = this.isConstructed; + object.isHexOnly = this.isHexOnly; + object.valueHex = (0, _pvutils.bufferToHexCodes)(this.valueHex, 0, this.valueHex.byteLength); + + return object; + } + //********************************************************************************** +} +//************************************************************************************** +class OctetString extends BaseBlock { + //********************************************************************************** + /** + * Constructor for "OctetString" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) { + super(parameters, LocalOctetStringValueBlock); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 4; // OctetString + } + //********************************************************************************** + /** + * Base function for converting block from BER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {number} Offset after least decoded byte + */ + fromBER(inputBuffer, inputOffset, inputLength) { + this.valueBlock.isConstructed = this.idBlock.isConstructed; + this.valueBlock.isIndefiniteForm = this.lenBlock.isIndefiniteForm; + + //region Ability to encode empty OCTET STRING + if (inputLength === 0) { + if (this.idBlock.error.length === 0) this.blockLength += this.idBlock.blockLength; + + if (this.lenBlock.error.length === 0) this.blockLength += this.lenBlock.blockLength; + + return inputOffset; + } + //endregion + + return super.fromBER(inputBuffer, inputOffset, inputLength); + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "OctetString"; + } + //********************************************************************************** + //noinspection JSUnusedGlobalSymbols + /** + * Checking that two OCTETSTRINGs are equal + * @param {OctetString} octetString + */ + isEqual(octetString) { + //region Check input type + if (octetString instanceof OctetString === false) return false; + //endregion + + //region Compare two JSON strings + if (JSON.stringify(this) !== JSON.stringify(octetString)) return false; + //endregion + + return true; + } + //********************************************************************************** +} +exports.OctetString = OctetString; //************************************************************************************** +//endregion +//************************************************************************************** +//region Declaration of ASN.1 BitString type class +//************************************************************************************** + +class LocalBitStringValueBlock extends LocalHexBlock(LocalConstructedValueBlock) { + //********************************************************************************** + /** + * Constructor for "LocalBitStringValueBlock" class + * @param {Object} [parameters={}] + * @property {ArrayBuffer} [valueHex] + */ + constructor(parameters = {}) { + super(parameters); + + this.unusedBits = (0, _pvutils.getParametersValue)(parameters, "unusedBits", 0); + this.isConstructed = (0, _pvutils.getParametersValue)(parameters, "isConstructed", false); + this.blockLength = this.valueHex.byteLength; + } + //********************************************************************************** + /** + * Base function for converting block from BER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {number} Offset after least decoded byte + */ + fromBER(inputBuffer, inputOffset, inputLength) { + //region Ability to decode zero-length BitString value + if (inputLength === 0) return inputOffset; + //endregion + + let resultOffset = -1; + + //region If the BISTRING supposed to be a constructed value + if (this.isConstructed === true) { + resultOffset = LocalConstructedValueBlock.prototype.fromBER.call(this, inputBuffer, inputOffset, inputLength); + if (resultOffset === -1) return resultOffset; + + for (let i = 0; i < this.value.length; i++) { + const currentBlockName = this.value[i].constructor.blockName(); + + if (currentBlockName === EndOfContent.blockName()) { + if (this.isIndefiniteForm === true) break;else { + this.error = "EndOfContent is unexpected, BIT STRING may consists of BIT STRINGs only"; + return -1; + } + } + + if (currentBlockName !== BitString.blockName()) { + this.error = "BIT STRING may consists of BIT STRINGs only"; + return -1; + } + + if (this.unusedBits > 0 && this.value[i].valueBlock.unusedBits > 0) { + this.error = "Usign of \"unused bits\" inside constructive BIT STRING allowed for least one only"; + return -1; + } + + this.unusedBits = this.value[i].valueBlock.unusedBits; + if (this.unusedBits > 7) { + this.error = "Unused bits for BitString must be in range 0-7"; + return -1; + } + } + + return resultOffset; + } + //endregion + //region If the BitString supposed to be a primitive value + //region Basic check for parameters + //noinspection JSCheckFunctionSignatures + if ((0, _pvutils.checkBufferParams)(this, inputBuffer, inputOffset, inputLength) === false) return -1; + //endregion + + const intBuffer = new Uint8Array(inputBuffer, inputOffset, inputLength); + + this.unusedBits = intBuffer[0]; + + if (this.unusedBits > 7) { + this.error = "Unused bits for BitString must be in range 0-7"; + return -1; + } + + //region Copy input buffer to internal buffer + this.valueHex = new ArrayBuffer(intBuffer.length - 1); + const view = new Uint8Array(this.valueHex); + for (let i = 0; i < inputLength - 1; i++) view[i] = intBuffer[i + 1]; + //endregion + + this.blockLength = intBuffer.length; + + return inputOffset + inputLength; + //endregion + } + //********************************************************************************** + /** + * Encoding of current ASN.1 block into ASN.1 encoded array (BER rules) + * @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes + * @returns {ArrayBuffer} + */ + toBER(sizeOnly = false) { + if (this.isConstructed === true) return LocalConstructedValueBlock.prototype.toBER.call(this, sizeOnly); + + if (sizeOnly === true) return new ArrayBuffer(this.valueHex.byteLength + 1); + + if (this.valueHex.byteLength === 0) return new ArrayBuffer(0); + + const curView = new Uint8Array(this.valueHex); + + const retBuf = new ArrayBuffer(this.valueHex.byteLength + 1); + const retView = new Uint8Array(retBuf); + + retView[0] = this.unusedBits; + + for (let i = 0; i < this.valueHex.byteLength; i++) retView[i + 1] = curView[i]; + + return retBuf; + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "BitStringValueBlock"; + } + //********************************************************************************** + /** + * Convertion for the block to JSON object + * @returns {{blockName, blockLength, error, warnings, valueBeforeDecode}|{blockName: string, blockLength: number, error: string, warnings: Array., valueBeforeDecode: string}} + */ + toJSON() { + let object = {}; + + //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object + try { + object = super.toJSON(); + } catch (ex) {} + //endregion + + object.unusedBits = this.unusedBits; + object.isConstructed = this.isConstructed; + object.isHexOnly = this.isHexOnly; + object.valueHex = (0, _pvutils.bufferToHexCodes)(this.valueHex, 0, this.valueHex.byteLength); + + return object; + } + //********************************************************************************** +} +//************************************************************************************** +class BitString extends BaseBlock { + //********************************************************************************** + /** + * Constructor for "BitString" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) { + super(parameters, LocalBitStringValueBlock); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 3; // BitString + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "BitString"; + } + //********************************************************************************** + /** + * Base function for converting block from BER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {number} Offset after least decoded byte + */ + fromBER(inputBuffer, inputOffset, inputLength) { + //region Ability to encode empty BitString + if (inputLength === 0) return inputOffset; + //endregion + + this.valueBlock.isConstructed = this.idBlock.isConstructed; + this.valueBlock.isIndefiniteForm = this.lenBlock.isIndefiniteForm; + + return super.fromBER(inputBuffer, inputOffset, inputLength); + } + //********************************************************************************** + /** + * Checking that two BITSTRINGs are equal + * @param {BitString} bitString + */ + isEqual(bitString) { + //region Check input type + if (bitString instanceof BitString === false) return false; + //endregion + + //region Compare two JSON strings + if (JSON.stringify(this) !== JSON.stringify(bitString)) return false; + //endregion + + return true; + } + //********************************************************************************** +} +exports.BitString = BitString; //************************************************************************************** +//endregion +//************************************************************************************** +//region Declaration of ASN.1 Integer type class +//************************************************************************************** +/** + * @extends LocalValueBlock + */ + +class LocalIntegerValueBlock extends LocalHexBlock(LocalValueBlock) { + //********************************************************************************** + /** + * Constructor for "LocalIntegerValueBlock" class + * @param {Object} [parameters={}] + * @property {ArrayBuffer} [valueHex] + */ + constructor(parameters = {}) { + super(parameters); + + if ("value" in parameters) this.valueDec = parameters.value; + } + //********************************************************************************** + /** + * Setter for "valueHex" + * @param {ArrayBuffer} _value + */ + set valueHex(_value) { + this._valueHex = _value.slice(0); + + if (_value.byteLength >= 4) { + this.warnings.push("Too big Integer for decoding, hex only"); + this.isHexOnly = true; + this._valueDec = 0; + } else { + this.isHexOnly = false; + + if (_value.byteLength > 0) this._valueDec = _pvutils.utilDecodeTC.call(this); + } + } + //********************************************************************************** + /** + * Getter for "valueHex" + * @returns {ArrayBuffer} + */ + get valueHex() { + return this._valueHex; + } + //********************************************************************************** + /** + * Getter for "valueDec" + * @param {number} _value + */ + set valueDec(_value) { + this._valueDec = _value; + + this.isHexOnly = false; + this._valueHex = (0, _pvutils.utilEncodeTC)(_value); + } + //********************************************************************************** + /** + * Getter for "valueDec" + * @returns {number} + */ + get valueDec() { + return this._valueDec; + } + //********************************************************************************** + /** + * Base function for converting block from DER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 DER encoded array + * @param {!number} inputOffset Offset in ASN.1 DER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @param {number} [expectedLength=0] Expected length of converted "valueHex" buffer + * @returns {number} Offset after least decoded byte + */ + fromDER(inputBuffer, inputOffset, inputLength, expectedLength = 0) { + const offset = this.fromBER(inputBuffer, inputOffset, inputLength); + if (offset === -1) return offset; + + const view = new Uint8Array(this._valueHex); + + if (view[0] === 0x00 && (view[1] & 0x80) !== 0) { + const updatedValueHex = new ArrayBuffer(this._valueHex.byteLength - 1); + const updatedView = new Uint8Array(updatedValueHex); + + updatedView.set(new Uint8Array(this._valueHex, 1, this._valueHex.byteLength - 1)); + + this._valueHex = updatedValueHex.slice(0); + } else { + if (expectedLength !== 0) { + if (this._valueHex.byteLength < expectedLength) { + if (expectedLength - this._valueHex.byteLength > 1) expectedLength = this._valueHex.byteLength + 1; + + const updatedValueHex = new ArrayBuffer(expectedLength); + const updatedView = new Uint8Array(updatedValueHex); + + updatedView.set(view, expectedLength - this._valueHex.byteLength); + + this._valueHex = updatedValueHex.slice(0); + } + } + } + + return offset; + } + //********************************************************************************** + /** + * Encoding of current ASN.1 block into ASN.1 encoded array (DER rules) + * @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes + * @returns {ArrayBuffer} + */ + toDER(sizeOnly = false) { + const view = new Uint8Array(this._valueHex); + + switch (true) { + case (view[0] & 0x80) !== 0: + { + const updatedValueHex = new ArrayBuffer(this._valueHex.byteLength + 1); + const updatedView = new Uint8Array(updatedValueHex); + + updatedView[0] = 0x00; + updatedView.set(view, 1); + + this._valueHex = updatedValueHex.slice(0); + } + break; + case view[0] === 0x00 && (view[1] & 0x80) === 0: + { + const updatedValueHex = new ArrayBuffer(this._valueHex.byteLength - 1); + const updatedView = new Uint8Array(updatedValueHex); + + updatedView.set(new Uint8Array(this._valueHex, 1, this._valueHex.byteLength - 1)); + + this._valueHex = updatedValueHex.slice(0); + } + break; + default: + } + + return this.toBER(sizeOnly); + } + //********************************************************************************** + /** + * Base function for converting block from BER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {number} Offset after least decoded byte + */ + fromBER(inputBuffer, inputOffset, inputLength) { + const resultOffset = super.fromBER(inputBuffer, inputOffset, inputLength); + if (resultOffset === -1) return resultOffset; + + this.blockLength = inputLength; + + return inputOffset + inputLength; + } + //********************************************************************************** + /** + * Encoding of current ASN.1 block into ASN.1 encoded array (BER rules) + * @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes + * @returns {ArrayBuffer} + */ + toBER(sizeOnly = false) { + //noinspection JSCheckFunctionSignatures + return this.valueHex.slice(0); + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "IntegerValueBlock"; + } + //********************************************************************************** + //noinspection JSUnusedGlobalSymbols + /** + * Convertion for the block to JSON object + * @returns {Object} + */ + toJSON() { + let object = {}; + + //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object + try { + object = super.toJSON(); + } catch (ex) {} + //endregion + + object.valueDec = this.valueDec; + + return object; + } + //********************************************************************************** + /** + * Convert current value to decimal string representation + */ + toString() { + //region Aux functions + function viewAdd(first, second) { + //region Initial variables + const c = new Uint8Array([0]); + + let firstView = new Uint8Array(first); + let secondView = new Uint8Array(second); + + let firstViewCopy = firstView.slice(0); + const firstViewCopyLength = firstViewCopy.length - 1; + let secondViewCopy = secondView.slice(0); + const secondViewCopyLength = secondViewCopy.length - 1; + + let value = 0; + + const max = secondViewCopyLength < firstViewCopyLength ? firstViewCopyLength : secondViewCopyLength; + + let counter = 0; + //endregion + + for (let i = max; i >= 0; i--, counter++) { + switch (true) { + case counter < secondViewCopy.length: + value = firstViewCopy[firstViewCopyLength - counter] + secondViewCopy[secondViewCopyLength - counter] + c[0]; + break; + default: + value = firstViewCopy[firstViewCopyLength - counter] + c[0]; + } + + c[0] = value / 10; + + switch (true) { + case counter >= firstViewCopy.length: + firstViewCopy = (0, _pvutils.utilConcatView)(new Uint8Array([value % 10]), firstViewCopy); + break; + default: + firstViewCopy[firstViewCopyLength - counter] = value % 10; + } + } + + if (c[0] > 0) firstViewCopy = (0, _pvutils.utilConcatView)(c, firstViewCopy); + + return firstViewCopy.slice(0); + } + + function power2(n) { + if (n >= powers2.length) { + for (let p = powers2.length; p <= n; p++) { + const c = new Uint8Array([0]); + let digits = powers2[p - 1].slice(0); + + for (let i = digits.length - 1; i >= 0; i--) { + const newValue = new Uint8Array([(digits[i] << 1) + c[0]]); + c[0] = newValue[0] / 10; + digits[i] = newValue[0] % 10; + } + + if (c[0] > 0) digits = (0, _pvutils.utilConcatView)(c, digits); + + powers2.push(digits); + } + } + + return powers2[n]; + } + + function viewSub(first, second) { + //region Initial variables + let b = 0; + + let firstView = new Uint8Array(first); + let secondView = new Uint8Array(second); + + let firstViewCopy = firstView.slice(0); + const firstViewCopyLength = firstViewCopy.length - 1; + let secondViewCopy = secondView.slice(0); + const secondViewCopyLength = secondViewCopy.length - 1; + + let value; + + let counter = 0; + //endregion + + for (let i = secondViewCopyLength; i >= 0; i--, counter++) { + value = firstViewCopy[firstViewCopyLength - counter] - secondViewCopy[secondViewCopyLength - counter] - b; + + switch (true) { + case value < 0: + b = 1; + firstViewCopy[firstViewCopyLength - counter] = value + 10; + break; + default: + b = 0; + firstViewCopy[firstViewCopyLength - counter] = value; + } + } + + if (b > 0) { + for (let i = firstViewCopyLength - secondViewCopyLength + 1; i >= 0; i--, counter++) { + value = firstViewCopy[firstViewCopyLength - counter] - b; + + if (value < 0) { + b = 1; + firstViewCopy[firstViewCopyLength - counter] = value + 10; + } else { + b = 0; + firstViewCopy[firstViewCopyLength - counter] = value; + break; + } + } + } + + return firstViewCopy.slice(); + } + //endregion + + //region Initial variables + const firstBit = this._valueHex.byteLength * 8 - 1; + + let digits = new Uint8Array(this._valueHex.byteLength * 8 / 3); + let bitNumber = 0; + let currentByte; + + const asn1View = new Uint8Array(this._valueHex); + + let result = ""; + + let flag = false; + //endregion + + //region Calculate number + for (let byteNumber = this._valueHex.byteLength - 1; byteNumber >= 0; byteNumber--) { + currentByte = asn1View[byteNumber]; + + for (let i = 0; i < 8; i++) { + if ((currentByte & 1) === 1) { + switch (bitNumber) { + case firstBit: + digits = viewSub(power2(bitNumber), digits); + result = "-"; + break; + default: + digits = viewAdd(digits, power2(bitNumber)); + } + } + + bitNumber++; + currentByte >>= 1; + } + } + //endregion + + //region Print number + for (let i = 0; i < digits.length; i++) { + if (digits[i]) flag = true; + + if (flag) result += digitsString.charAt(digits[i]); + } + + if (flag === false) result += digitsString.charAt(0); + //endregion + + return result; + } + //********************************************************************************** +} +//************************************************************************************** +class Integer extends BaseBlock { + //********************************************************************************** + /** + * Constructor for "Integer" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) { + super(parameters, LocalIntegerValueBlock); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 2; // Integer + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "Integer"; + } + //********************************************************************************** + //noinspection JSUnusedGlobalSymbols + /** + * Compare two Integer object, or Integer and ArrayBuffer objects + * @param {!Integer|ArrayBuffer} otherValue + * @returns {boolean} + */ + isEqual(otherValue) { + if (otherValue instanceof Integer) { + if (this.valueBlock.isHexOnly && otherValue.valueBlock.isHexOnly) // Compare two ArrayBuffers + return (0, _pvutils.isEqualBuffer)(this.valueBlock.valueHex, otherValue.valueBlock.valueHex); + + if (this.valueBlock.isHexOnly === otherValue.valueBlock.isHexOnly) return this.valueBlock.valueDec === otherValue.valueBlock.valueDec; + + return false; + } + + if (otherValue instanceof ArrayBuffer) return (0, _pvutils.isEqualBuffer)(this.valueBlock.valueHex, otherValue); + + return false; + } + //********************************************************************************** + /** + * Convert current Integer value from BER into DER format + * @returns {Integer} + */ + convertToDER() { + const integer = new Integer({ valueHex: this.valueBlock.valueHex }); + integer.valueBlock.toDER(); + + return integer; + } + //********************************************************************************** + /** + * Convert current Integer value from DER to BER format + * @returns {Integer} + */ + convertFromDER() { + const expectedLength = this.valueBlock.valueHex.byteLength % 2 ? this.valueBlock.valueHex.byteLength + 1 : this.valueBlock.valueHex.byteLength; + const integer = new Integer({ valueHex: this.valueBlock.valueHex }); + integer.valueBlock.fromDER(integer.valueBlock.valueHex, 0, integer.valueBlock.valueHex.byteLength, expectedLength); + + return integer; + } + //********************************************************************************** +} +exports.Integer = Integer; //************************************************************************************** +//endregion +//************************************************************************************** +//region Declaration of ASN.1 Enumerated type class +//************************************************************************************** + +class Enumerated extends Integer { + //********************************************************************************** + /** + * Constructor for "Enumerated" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) { + super(parameters); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 10; // Enumerated + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "Enumerated"; + } + //********************************************************************************** +} +exports.Enumerated = Enumerated; //************************************************************************************** +//endregion +//************************************************************************************** +//region Declaration of ASN.1 ObjectIdentifier type class +//************************************************************************************** + +class LocalSidValueBlock extends LocalHexBlock(LocalBaseBlock) { + //********************************************************************************** + /** + * Constructor for "LocalSidValueBlock" class + * @param {Object} [parameters={}] + * @property {number} [valueDec] + * @property {boolean} [isFirstSid] + */ + constructor(parameters = {}) { + super(parameters); + + this.valueDec = (0, _pvutils.getParametersValue)(parameters, "valueDec", -1); + this.isFirstSid = (0, _pvutils.getParametersValue)(parameters, "isFirstSid", false); + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "sidBlock"; + } + //********************************************************************************** + /** + * Base function for converting block from BER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {number} Offset after least decoded byte + */ + fromBER(inputBuffer, inputOffset, inputLength) { + if (inputLength === 0) return inputOffset; + + //region Basic check for parameters + //noinspection JSCheckFunctionSignatures + if ((0, _pvutils.checkBufferParams)(this, inputBuffer, inputOffset, inputLength) === false) return -1; + //endregion + + const intBuffer = new Uint8Array(inputBuffer, inputOffset, inputLength); + + this.valueHex = new ArrayBuffer(inputLength); + let view = new Uint8Array(this.valueHex); + + for (let i = 0; i < inputLength; i++) { + view[i] = intBuffer[i] & 0x7F; + + this.blockLength++; + + if ((intBuffer[i] & 0x80) === 0x00) break; + } + + //region Ajust size of valueHex buffer + const tempValueHex = new ArrayBuffer(this.blockLength); + const tempView = new Uint8Array(tempValueHex); + + for (let i = 0; i < this.blockLength; i++) tempView[i] = view[i]; + + //noinspection JSCheckFunctionSignatures + this.valueHex = tempValueHex.slice(0); + view = new Uint8Array(this.valueHex); + //endregion + + if ((intBuffer[this.blockLength - 1] & 0x80) !== 0x00) { + this.error = "End of input reached before message was fully decoded"; + return -1; + } + + if (view[0] === 0x00) this.warnings.push("Needlessly long format of SID encoding"); + + if (this.blockLength <= 8) this.valueDec = (0, _pvutils.utilFromBase)(view, 7);else { + this.isHexOnly = true; + this.warnings.push("Too big SID for decoding, hex only"); + } + + return inputOffset + this.blockLength; + } + //********************************************************************************** + /** + * Encoding of current ASN.1 block into ASN.1 encoded array (BER rules) + * @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes + * @returns {ArrayBuffer} + */ + toBER(sizeOnly = false) { + //region Initial variables + let retBuf; + let retView; + //endregion + + if (this.isHexOnly) { + if (sizeOnly === true) return new ArrayBuffer(this.valueHex.byteLength); + + const curView = new Uint8Array(this.valueHex); + + retBuf = new ArrayBuffer(this.blockLength); + retView = new Uint8Array(retBuf); + + for (let i = 0; i < this.blockLength - 1; i++) retView[i] = curView[i] | 0x80; + + retView[this.blockLength - 1] = curView[this.blockLength - 1]; + + return retBuf; + } + + const encodedBuf = (0, _pvutils.utilToBase)(this.valueDec, 7); + if (encodedBuf.byteLength === 0) { + this.error = "Error during encoding SID value"; + return new ArrayBuffer(0); + } + + retBuf = new ArrayBuffer(encodedBuf.byteLength); + + if (sizeOnly === false) { + const encodedView = new Uint8Array(encodedBuf); + retView = new Uint8Array(retBuf); + + for (let i = 0; i < encodedBuf.byteLength - 1; i++) retView[i] = encodedView[i] | 0x80; + + retView[encodedBuf.byteLength - 1] = encodedView[encodedBuf.byteLength - 1]; + } + + return retBuf; + } + //********************************************************************************** + /** + * Create string representation of current SID block + * @returns {string} + */ + toString() { + let result = ""; + + if (this.isHexOnly === true) result = (0, _pvutils.bufferToHexCodes)(this.valueHex, 0, this.valueHex.byteLength);else { + if (this.isFirstSid) { + let sidValue = this.valueDec; + + if (this.valueDec <= 39) result = "0.";else { + if (this.valueDec <= 79) { + result = "1."; + sidValue -= 40; + } else { + result = "2."; + sidValue -= 80; + } + } + + result += sidValue.toString(); + } else result = this.valueDec.toString(); + } + + return result; + } + //********************************************************************************** + //noinspection JSUnusedGlobalSymbols + /** + * Convertion for the block to JSON object + * @returns {Object} + */ + toJSON() { + let object = {}; + + //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object + try { + object = super.toJSON(); + } catch (ex) {} + //endregion + + object.valueDec = this.valueDec; + object.isFirstSid = this.isFirstSid; + + return object; + } + //********************************************************************************** +} +//************************************************************************************** +class LocalObjectIdentifierValueBlock extends LocalValueBlock { + //********************************************************************************** + /** + * Constructor for "LocalObjectIdentifierValueBlock" class + * @param {Object} [parameters={}] + * @property {ArrayBuffer} [valueHex] + */ + constructor(parameters = {}) { + super(parameters); + + this.fromString((0, _pvutils.getParametersValue)(parameters, "value", "")); + } + //********************************************************************************** + /** + * Base function for converting block from BER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {number} Offset after least decoded byte + */ + fromBER(inputBuffer, inputOffset, inputLength) { + let resultOffset = inputOffset; + + while (inputLength > 0) { + const sidBlock = new LocalSidValueBlock(); + resultOffset = sidBlock.fromBER(inputBuffer, resultOffset, inputLength); + if (resultOffset === -1) { + this.blockLength = 0; + this.error = sidBlock.error; + return resultOffset; + } + + if (this.value.length === 0) sidBlock.isFirstSid = true; + + this.blockLength += sidBlock.blockLength; + inputLength -= sidBlock.blockLength; + + this.value.push(sidBlock); + } + + return resultOffset; + } + //********************************************************************************** + /** + * Encoding of current ASN.1 block into ASN.1 encoded array (BER rules) + * @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes + * @returns {ArrayBuffer} + */ + toBER(sizeOnly = false) { + let retBuf = new ArrayBuffer(0); + + for (let i = 0; i < this.value.length; i++) { + const valueBuf = this.value[i].toBER(sizeOnly); + if (valueBuf.byteLength === 0) { + this.error = this.value[i].error; + return new ArrayBuffer(0); + } + + retBuf = (0, _pvutils.utilConcatBuf)(retBuf, valueBuf); + } + + return retBuf; + } + //********************************************************************************** + /** + * Create "LocalObjectIdentifierValueBlock" class from string + * @param {string} string Input string to convert from + * @returns {boolean} + */ + fromString(string) { + this.value = []; // Clear existing SID values + + let pos1 = 0; + let pos2 = 0; + + let sid = ""; + + let flag = false; + + do { + pos2 = string.indexOf(".", pos1); + if (pos2 === -1) sid = string.substr(pos1);else sid = string.substr(pos1, pos2 - pos1); + + pos1 = pos2 + 1; + + if (flag) { + const sidBlock = this.value[0]; + + let plus = 0; + + switch (sidBlock.valueDec) { + case 0: + break; + case 1: + plus = 40; + break; + case 2: + plus = 80; + break; + default: + this.value = []; // clear SID array + return false; // ??? + } + + const parsedSID = parseInt(sid, 10); + if (isNaN(parsedSID)) return true; + + sidBlock.valueDec = parsedSID + plus; + + flag = false; + } else { + const sidBlock = new LocalSidValueBlock(); + sidBlock.valueDec = parseInt(sid, 10); + if (isNaN(sidBlock.valueDec)) return true; + + if (this.value.length === 0) { + sidBlock.isFirstSid = true; + flag = true; + } + + this.value.push(sidBlock); + } + } while (pos2 !== -1); + + return true; + } + //********************************************************************************** + /** + * Converts "LocalObjectIdentifierValueBlock" class to string + * @returns {string} + */ + toString() { + let result = ""; + let isHexOnly = false; + + for (let i = 0; i < this.value.length; i++) { + isHexOnly = this.value[i].isHexOnly; + + let sidStr = this.value[i].toString(); + + if (i !== 0) result = `${result}.`; + + if (isHexOnly) { + sidStr = `{${sidStr}}`; + + if (this.value[i].isFirstSid) result = `2.{${sidStr} - 80}`;else result += sidStr; + } else result += sidStr; + } + + return result; + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "ObjectIdentifierValueBlock"; + } + //********************************************************************************** + /** + * Convertion for the block to JSON object + * @returns {Object} + */ + toJSON() { + let object = {}; + + //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object + try { + object = super.toJSON(); + } catch (ex) {} + //endregion + + object.value = this.toString(); + object.sidArray = []; + for (let i = 0; i < this.value.length; i++) object.sidArray.push(this.value[i].toJSON()); + + return object; + } + //********************************************************************************** +} +//************************************************************************************** +/** + * @extends BaseBlock + */ +class ObjectIdentifier extends BaseBlock { + //********************************************************************************** + /** + * Constructor for "ObjectIdentifier" class + * @param {Object} [parameters={}] + * @property {ArrayBuffer} [valueHex] + */ + constructor(parameters = {}) { + super(parameters, LocalObjectIdentifierValueBlock); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 6; // OBJECT IDENTIFIER + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "ObjectIdentifier"; + } + //********************************************************************************** +} +exports.ObjectIdentifier = ObjectIdentifier; //************************************************************************************** +//endregion +//************************************************************************************** +//region Declaration of all string's classes +//************************************************************************************** + +class LocalUtf8StringValueBlock extends LocalHexBlock(LocalBaseBlock) { + //********************************************************************************** + //noinspection JSUnusedGlobalSymbols + /** + * Constructor for "LocalUtf8StringValueBlock" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) { + super(parameters); + + this.isHexOnly = true; + this.value = ""; // String representation of decoded ArrayBuffer + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "Utf8StringValueBlock"; + } + //********************************************************************************** + //noinspection JSUnusedGlobalSymbols + /** + * Convertion for the block to JSON object + * @returns {Object} + */ + toJSON() { + let object = {}; + + //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object + try { + object = super.toJSON(); + } catch (ex) {} + //endregion + + object.value = this.value; + + return object; + } + //********************************************************************************** +} +//************************************************************************************** +/** + * @extends BaseBlock + */ +class Utf8String extends BaseBlock { + //********************************************************************************** + /** + * Constructor for "Utf8String" class + * @param {Object} [parameters={}] + * @property {ArrayBuffer} [valueHex] + */ + constructor(parameters = {}) { + super(parameters, LocalUtf8StringValueBlock); + + if ("value" in parameters) this.fromString(parameters.value); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 12; // Utf8String + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "Utf8String"; + } + //********************************************************************************** + /** + * Base function for converting block from BER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {number} Offset after least decoded byte + */ + fromBER(inputBuffer, inputOffset, inputLength) { + const resultOffset = this.valueBlock.fromBER(inputBuffer, inputOffset, this.lenBlock.isIndefiniteForm === true ? inputLength : this.lenBlock.length); + if (resultOffset === -1) { + this.error = this.valueBlock.error; + return resultOffset; + } + + this.fromBuffer(this.valueBlock.valueHex); + + if (this.idBlock.error.length === 0) this.blockLength += this.idBlock.blockLength; + + if (this.lenBlock.error.length === 0) this.blockLength += this.lenBlock.blockLength; + + if (this.valueBlock.error.length === 0) this.blockLength += this.valueBlock.blockLength; + + return resultOffset; + } + //********************************************************************************** + /** + * Function converting ArrayBuffer into ASN.1 internal string + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + */ + fromBuffer(inputBuffer) { + this.valueBlock.value = String.fromCharCode.apply(null, new Uint8Array(inputBuffer)); + + try { + //noinspection JSDeprecatedSymbols + this.valueBlock.value = decodeURIComponent(escape(this.valueBlock.value)); + } catch (ex) { + this.warnings.push(`Error during "decodeURIComponent": ${ex}, using raw string`); + } + } + //********************************************************************************** + /** + * Function converting JavaScript string into ASN.1 internal class + * @param {!string} inputString ASN.1 BER encoded array + */ + fromString(inputString) { + //noinspection JSDeprecatedSymbols + const str = unescape(encodeURIComponent(inputString)); + const strLen = str.length; + + this.valueBlock.valueHex = new ArrayBuffer(strLen); + const view = new Uint8Array(this.valueBlock.valueHex); + + for (let i = 0; i < strLen; i++) view[i] = str.charCodeAt(i); + + this.valueBlock.value = inputString; + } + //********************************************************************************** +} +exports.Utf8String = Utf8String; //************************************************************************************** +/** + * @extends LocalBaseBlock + * @extends LocalHexBlock + */ + +class LocalBmpStringValueBlock extends LocalHexBlock(LocalBaseBlock) { + //********************************************************************************** + /** + * Constructor for "LocalBmpStringValueBlock" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) { + super(parameters); + + this.isHexOnly = true; + this.value = ""; + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "BmpStringValueBlock"; + } + //********************************************************************************** + //noinspection JSUnusedGlobalSymbols + /** + * Convertion for the block to JSON object + * @returns {Object} + */ + toJSON() { + let object = {}; + + //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object + try { + object = super.toJSON(); + } catch (ex) {} + //endregion + + object.value = this.value; + + return object; + } + //********************************************************************************** +} +//************************************************************************************** +/** + * @extends BaseBlock + */ +class BmpString extends BaseBlock { + //********************************************************************************** + /** + * Constructor for "BmpString" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) { + super(parameters, LocalBmpStringValueBlock); + + if ("value" in parameters) this.fromString(parameters.value); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 30; // BmpString + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "BmpString"; + } + //********************************************************************************** + /** + * Base function for converting block from BER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {number} Offset after least decoded byte + */ + fromBER(inputBuffer, inputOffset, inputLength) { + const resultOffset = this.valueBlock.fromBER(inputBuffer, inputOffset, this.lenBlock.isIndefiniteForm === true ? inputLength : this.lenBlock.length); + if (resultOffset === -1) { + this.error = this.valueBlock.error; + return resultOffset; + } + + this.fromBuffer(this.valueBlock.valueHex); + + if (this.idBlock.error.length === 0) this.blockLength += this.idBlock.blockLength; + + if (this.lenBlock.error.length === 0) this.blockLength += this.lenBlock.blockLength; + + if (this.valueBlock.error.length === 0) this.blockLength += this.valueBlock.blockLength; + + return resultOffset; + } + //********************************************************************************** + /** + * Function converting ArrayBuffer into ASN.1 internal string + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + */ + fromBuffer(inputBuffer) { + //noinspection JSCheckFunctionSignatures + const copyBuffer = inputBuffer.slice(0); + const valueView = new Uint8Array(copyBuffer); + + for (let i = 0; i < valueView.length; i += 2) { + const temp = valueView[i]; + + valueView[i] = valueView[i + 1]; + valueView[i + 1] = temp; + } + + this.valueBlock.value = String.fromCharCode.apply(null, new Uint16Array(copyBuffer)); + } + //********************************************************************************** + /** + * Function converting JavaScript string into ASN.1 internal class + * @param {!string} inputString ASN.1 BER encoded array + */ + fromString(inputString) { + const strLength = inputString.length; + + this.valueBlock.valueHex = new ArrayBuffer(strLength * 2); + const valueHexView = new Uint8Array(this.valueBlock.valueHex); + + for (let i = 0; i < strLength; i++) { + const codeBuf = (0, _pvutils.utilToBase)(inputString.charCodeAt(i), 8); + const codeView = new Uint8Array(codeBuf); + if (codeView.length > 2) continue; + + const dif = 2 - codeView.length; + + for (let j = codeView.length - 1; j >= 0; j--) valueHexView[i * 2 + j + dif] = codeView[j]; + } + + this.valueBlock.value = inputString; + } + //********************************************************************************** +} +exports.BmpString = BmpString; //************************************************************************************** + +class LocalUniversalStringValueBlock extends LocalHexBlock(LocalBaseBlock) { + //********************************************************************************** + /** + * Constructor for "LocalUniversalStringValueBlock" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) { + super(parameters); + + this.isHexOnly = true; + this.value = ""; + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "UniversalStringValueBlock"; + } + //********************************************************************************** + //noinspection JSUnusedGlobalSymbols + /** + * Convertion for the block to JSON object + * @returns {Object} + */ + toJSON() { + let object = {}; + + //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object + try { + object = super.toJSON(); + } catch (ex) {} + //endregion + + object.value = this.value; + + return object; + } + //********************************************************************************** +} +//************************************************************************************** +/** + * @extends BaseBlock + */ +class UniversalString extends BaseBlock { + //********************************************************************************** + /** + * Constructor for "UniversalString" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) { + super(parameters, LocalUniversalStringValueBlock); + + if ("value" in parameters) this.fromString(parameters.value); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 28; // UniversalString + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "UniversalString"; + } + //********************************************************************************** + /** + * Base function for converting block from BER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {number} Offset after least decoded byte + */ + fromBER(inputBuffer, inputOffset, inputLength) { + const resultOffset = this.valueBlock.fromBER(inputBuffer, inputOffset, this.lenBlock.isIndefiniteForm === true ? inputLength : this.lenBlock.length); + if (resultOffset === -1) { + this.error = this.valueBlock.error; + return resultOffset; + } + + this.fromBuffer(this.valueBlock.valueHex); + + if (this.idBlock.error.length === 0) this.blockLength += this.idBlock.blockLength; + + if (this.lenBlock.error.length === 0) this.blockLength += this.lenBlock.blockLength; + + if (this.valueBlock.error.length === 0) this.blockLength += this.valueBlock.blockLength; + + return resultOffset; + } + //********************************************************************************** + /** + * Function converting ArrayBuffer into ASN.1 internal string + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + */ + fromBuffer(inputBuffer) { + //noinspection JSCheckFunctionSignatures + const copyBuffer = inputBuffer.slice(0); + const valueView = new Uint8Array(copyBuffer); + + for (let i = 0; i < valueView.length; i += 4) { + valueView[i] = valueView[i + 3]; + valueView[i + 1] = valueView[i + 2]; + valueView[i + 2] = 0x00; + valueView[i + 3] = 0x00; + } + + this.valueBlock.value = String.fromCharCode.apply(null, new Uint32Array(copyBuffer)); + } + //********************************************************************************** + /** + * Function converting JavaScript string into ASN.1 internal class + * @param {!string} inputString ASN.1 BER encoded array + */ + fromString(inputString) { + const strLength = inputString.length; + + this.valueBlock.valueHex = new ArrayBuffer(strLength * 4); + const valueHexView = new Uint8Array(this.valueBlock.valueHex); + + for (let i = 0; i < strLength; i++) { + const codeBuf = (0, _pvutils.utilToBase)(inputString.charCodeAt(i), 8); + const codeView = new Uint8Array(codeBuf); + if (codeView.length > 4) continue; + + const dif = 4 - codeView.length; + + for (let j = codeView.length - 1; j >= 0; j--) valueHexView[i * 4 + j + dif] = codeView[j]; + } + + this.valueBlock.value = inputString; + } + //********************************************************************************** +} +exports.UniversalString = UniversalString; //************************************************************************************** + +class LocalSimpleStringValueBlock extends LocalHexBlock(LocalBaseBlock) { + //********************************************************************************** + /** + * Constructor for "LocalSimpleStringValueBlock" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) { + super(parameters); + + this.value = ""; + this.isHexOnly = true; + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "SimpleStringValueBlock"; + } + //********************************************************************************** + //noinspection JSUnusedGlobalSymbols + /** + * Convertion for the block to JSON object + * @returns {Object} + */ + toJSON() { + let object = {}; + + //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object + try { + object = super.toJSON(); + } catch (ex) {} + //endregion + + object.value = this.value; + + return object; + } + //********************************************************************************** +} +//************************************************************************************** +/** + * @extends BaseBlock + */ +class LocalSimpleStringBlock extends BaseBlock { + //********************************************************************************** + /** + * Constructor for "LocalSimpleStringBlock" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) { + super(parameters, LocalSimpleStringValueBlock); + + if ("value" in parameters) this.fromString(parameters.value); + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "SIMPLESTRING"; + } + //********************************************************************************** + /** + * Base function for converting block from BER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {number} Offset after least decoded byte + */ + fromBER(inputBuffer, inputOffset, inputLength) { + const resultOffset = this.valueBlock.fromBER(inputBuffer, inputOffset, this.lenBlock.isIndefiniteForm === true ? inputLength : this.lenBlock.length); + if (resultOffset === -1) { + this.error = this.valueBlock.error; + return resultOffset; + } + + this.fromBuffer(this.valueBlock.valueHex); + + if (this.idBlock.error.length === 0) this.blockLength += this.idBlock.blockLength; + + if (this.lenBlock.error.length === 0) this.blockLength += this.lenBlock.blockLength; + + if (this.valueBlock.error.length === 0) this.blockLength += this.valueBlock.blockLength; + + return resultOffset; + } + //********************************************************************************** + /** + * Function converting ArrayBuffer into ASN.1 internal string + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + */ + fromBuffer(inputBuffer) { + this.valueBlock.value = String.fromCharCode.apply(null, new Uint8Array(inputBuffer)); + } + //********************************************************************************** + /** + * Function converting JavaScript string into ASN.1 internal class + * @param {!string} inputString ASN.1 BER encoded array + */ + fromString(inputString) { + const strLen = inputString.length; + + this.valueBlock.valueHex = new ArrayBuffer(strLen); + const view = new Uint8Array(this.valueBlock.valueHex); + + for (let i = 0; i < strLen; i++) view[i] = inputString.charCodeAt(i); + + this.valueBlock.value = inputString; + } + //********************************************************************************** +} +//************************************************************************************** +/** + * @extends LocalSimpleStringBlock + */ +class NumericString extends LocalSimpleStringBlock { + //********************************************************************************** + /** + * Constructor for "NumericString" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) { + super(parameters); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 18; // NumericString + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "NumericString"; + } + //********************************************************************************** +} +exports.NumericString = NumericString; //************************************************************************************** +/** + * @extends LocalSimpleStringBlock + */ + +class PrintableString extends LocalSimpleStringBlock { + //********************************************************************************** + /** + * Constructor for "PrintableString" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) { + super(parameters); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 19; // PrintableString + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "PrintableString"; + } + //********************************************************************************** +} +exports.PrintableString = PrintableString; //************************************************************************************** +/** + * @extends LocalSimpleStringBlock + */ + +class TeletexString extends LocalSimpleStringBlock { + //********************************************************************************** + /** + * Constructor for "TeletexString" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) { + super(parameters); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 20; // TeletexString + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "TeletexString"; + } + //********************************************************************************** +} +exports.TeletexString = TeletexString; //************************************************************************************** +/** + * @extends LocalSimpleStringBlock + */ + +class VideotexString extends LocalSimpleStringBlock { + //********************************************************************************** + /** + * Constructor for "VideotexString" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) { + super(parameters); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 21; // VideotexString + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "VideotexString"; + } + //********************************************************************************** +} +exports.VideotexString = VideotexString; //************************************************************************************** +/** + * @extends LocalSimpleStringBlock + */ + +class IA5String extends LocalSimpleStringBlock { + //********************************************************************************** + /** + * Constructor for "IA5String" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) { + super(parameters); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 22; // IA5String + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "IA5String"; + } + //********************************************************************************** +} +exports.IA5String = IA5String; //************************************************************************************** +/** + * @extends LocalSimpleStringBlock + */ + +class GraphicString extends LocalSimpleStringBlock { + //********************************************************************************** + /** + * Constructor for "GraphicString" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) { + super(parameters); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 25; // GraphicString + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "GraphicString"; + } + //********************************************************************************** +} +exports.GraphicString = GraphicString; //************************************************************************************** +/** + * @extends LocalSimpleStringBlock + */ + +class VisibleString extends LocalSimpleStringBlock { + //********************************************************************************** + /** + * Constructor for "VisibleString" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) { + super(parameters); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 26; // VisibleString + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "VisibleString"; + } + //********************************************************************************** +} +exports.VisibleString = VisibleString; //************************************************************************************** +/** + * @extends LocalSimpleStringBlock + */ + +class GeneralString extends LocalSimpleStringBlock { + //********************************************************************************** + /** + * Constructor for "GeneralString" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) { + super(parameters); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 27; // GeneralString + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "GeneralString"; + } + //********************************************************************************** +} +exports.GeneralString = GeneralString; //************************************************************************************** +/** + * @extends LocalSimpleStringBlock + */ + +class CharacterString extends LocalSimpleStringBlock { + //********************************************************************************** + /** + * Constructor for "CharacterString" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) { + super(parameters); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 29; // CharacterString + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "CharacterString"; + } + //********************************************************************************** +} +exports.CharacterString = CharacterString; //************************************************************************************** +//endregion +//************************************************************************************** +//region Declaration of all date and time classes +//************************************************************************************** +/** + * @extends VisibleString + */ + +class UTCTime extends VisibleString { + //********************************************************************************** + /** + * Constructor for "UTCTime" class + * @param {Object} [parameters={}] + * @property {string} [value] String representatio of the date + * @property {Date} [valueDate] JavaScript "Date" object + */ + constructor(parameters = {}) { + super(parameters); + + this.year = 0; + this.month = 0; + this.day = 0; + this.hour = 0; + this.minute = 0; + this.second = 0; + + //region Create UTCTime from ASN.1 UTC string value + if ("value" in parameters) { + this.fromString(parameters.value); + + this.valueBlock.valueHex = new ArrayBuffer(parameters.value.length); + const view = new Uint8Array(this.valueBlock.valueHex); + + for (let i = 0; i < parameters.value.length; i++) view[i] = parameters.value.charCodeAt(i); + } + //endregion + //region Create GeneralizedTime from JavaScript Date type + if ("valueDate" in parameters) { + this.fromDate(parameters.valueDate); + this.valueBlock.valueHex = this.toBuffer(); + } + //endregion + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 23; // UTCTime + } + //********************************************************************************** + /** + * Base function for converting block from BER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {number} Offset after least decoded byte + */ + fromBER(inputBuffer, inputOffset, inputLength) { + const resultOffset = this.valueBlock.fromBER(inputBuffer, inputOffset, this.lenBlock.isIndefiniteForm === true ? inputLength : this.lenBlock.length); + if (resultOffset === -1) { + this.error = this.valueBlock.error; + return resultOffset; + } + + this.fromBuffer(this.valueBlock.valueHex); + + if (this.idBlock.error.length === 0) this.blockLength += this.idBlock.blockLength; + + if (this.lenBlock.error.length === 0) this.blockLength += this.lenBlock.blockLength; + + if (this.valueBlock.error.length === 0) this.blockLength += this.valueBlock.blockLength; + + return resultOffset; + } + //********************************************************************************** + /** + * Function converting ArrayBuffer into ASN.1 internal string + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + */ + fromBuffer(inputBuffer) { + this.fromString(String.fromCharCode.apply(null, new Uint8Array(inputBuffer))); + } + //********************************************************************************** + /** + * Function converting ASN.1 internal string into ArrayBuffer + * @returns {ArrayBuffer} + */ + toBuffer() { + const str = this.toString(); + + const buffer = new ArrayBuffer(str.length); + const view = new Uint8Array(buffer); + + for (let i = 0; i < str.length; i++) view[i] = str.charCodeAt(i); + + return buffer; + } + //********************************************************************************** + /** + * Function converting "Date" object into ASN.1 internal string + * @param {!Date} inputDate JavaScript "Date" object + */ + fromDate(inputDate) { + this.year = inputDate.getUTCFullYear(); + this.month = inputDate.getUTCMonth() + 1; + this.day = inputDate.getUTCDate(); + this.hour = inputDate.getUTCHours(); + this.minute = inputDate.getUTCMinutes(); + this.second = inputDate.getUTCSeconds(); + } + //********************************************************************************** + //noinspection JSUnusedGlobalSymbols + /** + * Function converting ASN.1 internal string into "Date" object + * @returns {Date} + */ + toDate() { + return new Date(Date.UTC(this.year, this.month - 1, this.day, this.hour, this.minute, this.second)); + } + //********************************************************************************** + /** + * Function converting JavaScript string into ASN.1 internal class + * @param {!string} inputString ASN.1 BER encoded array + */ + fromString(inputString) { + //region Parse input string + const parser = /(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})Z/ig; + const parserArray = parser.exec(inputString); + if (parserArray === null) { + this.error = "Wrong input string for convertion"; + return; + } + //endregion + + //region Store parsed values + const year = parseInt(parserArray[1], 10); + if (year >= 50) this.year = 1900 + year;else this.year = 2000 + year; + + this.month = parseInt(parserArray[2], 10); + this.day = parseInt(parserArray[3], 10); + this.hour = parseInt(parserArray[4], 10); + this.minute = parseInt(parserArray[5], 10); + this.second = parseInt(parserArray[6], 10); + //endregion + } + //********************************************************************************** + /** + * Function converting ASN.1 internal class into JavaScript string + * @returns {string} + */ + toString() { + const outputArray = new Array(7); + + outputArray[0] = (0, _pvutils.padNumber)(this.year < 2000 ? this.year - 1900 : this.year - 2000, 2); + outputArray[1] = (0, _pvutils.padNumber)(this.month, 2); + outputArray[2] = (0, _pvutils.padNumber)(this.day, 2); + outputArray[3] = (0, _pvutils.padNumber)(this.hour, 2); + outputArray[4] = (0, _pvutils.padNumber)(this.minute, 2); + outputArray[5] = (0, _pvutils.padNumber)(this.second, 2); + outputArray[6] = "Z"; + + return outputArray.join(""); + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "UTCTime"; + } + //********************************************************************************** + /** + * Convertion for the block to JSON object + * @returns {Object} + */ + toJSON() { + let object = {}; + + //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object + try { + object = super.toJSON(); + } catch (ex) {} + //endregion + + object.year = this.year; + object.month = this.month; + object.day = this.day; + object.hour = this.hour; + object.minute = this.minute; + object.second = this.second; + + return object; + } + //********************************************************************************** +} +exports.UTCTime = UTCTime; //************************************************************************************** +/** + * @extends VisibleString + */ + +class GeneralizedTime extends VisibleString { + //********************************************************************************** + /** + * Constructor for "GeneralizedTime" class + * @param {Object} [parameters={}] + * @property {string} [value] String representatio of the date + * @property {Date} [valueDate] JavaScript "Date" object + */ + constructor(parameters = {}) { + super(parameters); + + this.year = 0; + this.month = 0; + this.day = 0; + this.hour = 0; + this.minute = 0; + this.second = 0; + this.millisecond = 0; + + //region Create UTCTime from ASN.1 UTC string value + if ("value" in parameters) { + this.fromString(parameters.value); + + this.valueBlock.valueHex = new ArrayBuffer(parameters.value.length); + const view = new Uint8Array(this.valueBlock.valueHex); + + for (let i = 0; i < parameters.value.length; i++) view[i] = parameters.value.charCodeAt(i); + } + //endregion + //region Create GeneralizedTime from JavaScript Date type + if ("valueDate" in parameters) { + this.fromDate(parameters.valueDate); + this.valueBlock.valueHex = this.toBuffer(); + } + //endregion + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 24; // GeneralizedTime + } + //********************************************************************************** + /** + * Base function for converting block from BER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {number} Offset after least decoded byte + */ + fromBER(inputBuffer, inputOffset, inputLength) { + const resultOffset = this.valueBlock.fromBER(inputBuffer, inputOffset, this.lenBlock.isIndefiniteForm === true ? inputLength : this.lenBlock.length); + if (resultOffset === -1) { + this.error = this.valueBlock.error; + return resultOffset; + } + + this.fromBuffer(this.valueBlock.valueHex); + + if (this.idBlock.error.length === 0) this.blockLength += this.idBlock.blockLength; + + if (this.lenBlock.error.length === 0) this.blockLength += this.lenBlock.blockLength; + + if (this.valueBlock.error.length === 0) this.blockLength += this.valueBlock.blockLength; + + return resultOffset; + } + //********************************************************************************** + /** + * Function converting ArrayBuffer into ASN.1 internal string + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + */ + fromBuffer(inputBuffer) { + this.fromString(String.fromCharCode.apply(null, new Uint8Array(inputBuffer))); + } + //********************************************************************************** + /** + * Function converting ASN.1 internal string into ArrayBuffer + * @returns {ArrayBuffer} + */ + toBuffer() { + const str = this.toString(); + + const buffer = new ArrayBuffer(str.length); + const view = new Uint8Array(buffer); + + for (let i = 0; i < str.length; i++) view[i] = str.charCodeAt(i); + + return buffer; + } + //********************************************************************************** + /** + * Function converting "Date" object into ASN.1 internal string + * @param {!Date} inputDate JavaScript "Date" object + */ + fromDate(inputDate) { + this.year = inputDate.getUTCFullYear(); + this.month = inputDate.getUTCMonth() + 1; + this.day = inputDate.getUTCDate(); + this.hour = inputDate.getUTCHours(); + this.minute = inputDate.getUTCMinutes(); + this.second = inputDate.getUTCSeconds(); + this.millisecond = inputDate.getUTCMilliseconds(); + } + //********************************************************************************** + //noinspection JSUnusedGlobalSymbols + /** + * Function converting ASN.1 internal string into "Date" object + * @returns {Date} + */ + toDate() { + return new Date(Date.UTC(this.year, this.month - 1, this.day, this.hour, this.minute, this.second, this.millisecond)); + } + //********************************************************************************** + /** + * Function converting JavaScript string into ASN.1 internal class + * @param {!string} inputString ASN.1 BER encoded array + */ + fromString(inputString) { + //region Initial variables + let isUTC = false; + + let timeString = ""; + let dateTimeString = ""; + let fractionPart = 0; + + let parser; + + let hourDifference = 0; + let minuteDifference = 0; + //endregion + + //region Convert as UTC time + if (inputString[inputString.length - 1] === "Z") { + timeString = inputString.substr(0, inputString.length - 1); + + isUTC = true; + } + //endregion + //region Convert as local time + else { + //noinspection JSPrimitiveTypeWrapperUsage + const number = new Number(inputString[inputString.length - 1]); + + if (isNaN(number.valueOf())) throw new Error("Wrong input string for convertion"); + + timeString = inputString; + } + //endregion + + //region Check that we do not have a "+" and "-" symbols inside UTC time + if (isUTC) { + if (timeString.indexOf("+") !== -1) throw new Error("Wrong input string for convertion"); + + if (timeString.indexOf("-") !== -1) throw new Error("Wrong input string for convertion"); + } + //endregion + //region Get "UTC time difference" in case of local time + else { + let multiplier = 1; + let differencePosition = timeString.indexOf("+"); + let differenceString = ""; + + if (differencePosition === -1) { + differencePosition = timeString.indexOf("-"); + multiplier = -1; + } + + if (differencePosition !== -1) { + differenceString = timeString.substr(differencePosition + 1); + timeString = timeString.substr(0, differencePosition); + + if (differenceString.length !== 2 && differenceString.length !== 4) throw new Error("Wrong input string for convertion"); + + //noinspection JSPrimitiveTypeWrapperUsage + let number = new Number(differenceString.substr(0, 2)); + + if (isNaN(number.valueOf())) throw new Error("Wrong input string for convertion"); + + hourDifference = multiplier * number; + + if (differenceString.length === 4) { + //noinspection JSPrimitiveTypeWrapperUsage + number = new Number(differenceString.substr(2, 2)); + + if (isNaN(number.valueOf())) throw new Error("Wrong input string for convertion"); + + minuteDifference = multiplier * number; + } + } + } + //endregion + + //region Get position of fraction point + let fractionPointPosition = timeString.indexOf("."); // Check for "full stop" symbol + if (fractionPointPosition === -1) fractionPointPosition = timeString.indexOf(","); // Check for "comma" symbol + //endregion + + //region Get fraction part + if (fractionPointPosition !== -1) { + //noinspection JSPrimitiveTypeWrapperUsage + const fractionPartCheck = new Number(`0${timeString.substr(fractionPointPosition)}`); + + if (isNaN(fractionPartCheck.valueOf())) throw new Error("Wrong input string for convertion"); + + fractionPart = fractionPartCheck.valueOf(); + + dateTimeString = timeString.substr(0, fractionPointPosition); + } else dateTimeString = timeString; + //endregion + + //region Parse internal date + switch (true) { + case dateTimeString.length === 8: + // "YYYYMMDD" + parser = /(\d{4})(\d{2})(\d{2})/ig; + if (fractionPointPosition !== -1) throw new Error("Wrong input string for convertion"); // Here we should not have a "fraction point" + break; + case dateTimeString.length === 10: + // "YYYYMMDDHH" + parser = /(\d{4})(\d{2})(\d{2})(\d{2})/ig; + + if (fractionPointPosition !== -1) { + let fractionResult = 60 * fractionPart; + this.minute = Math.floor(fractionResult); + + fractionResult = 60 * (fractionResult - this.minute); + this.second = Math.floor(fractionResult); + + fractionResult = 1000 * (fractionResult - this.second); + this.millisecond = Math.floor(fractionResult); + } + break; + case dateTimeString.length === 12: + // "YYYYMMDDHHMM" + parser = /(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})/ig; + + if (fractionPointPosition !== -1) { + let fractionResult = 60 * fractionPart; + this.second = Math.floor(fractionResult); + + fractionResult = 1000 * (fractionResult - this.second); + this.millisecond = Math.floor(fractionResult); + } + break; + case dateTimeString.length === 14: + // "YYYYMMDDHHMMSS" + parser = /(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/ig; + + if (fractionPointPosition !== -1) { + const fractionResult = 1000 * fractionPart; + this.millisecond = Math.floor(fractionResult); + } + break; + default: + throw new Error("Wrong input string for convertion"); + } + //endregion + + //region Put parsed values at right places + const parserArray = parser.exec(dateTimeString); + if (parserArray === null) throw new Error("Wrong input string for convertion"); + + for (let j = 1; j < parserArray.length; j++) { + switch (j) { + case 1: + this.year = parseInt(parserArray[j], 10); + break; + case 2: + this.month = parseInt(parserArray[j], 10); + break; + case 3: + this.day = parseInt(parserArray[j], 10); + break; + case 4: + this.hour = parseInt(parserArray[j], 10) + hourDifference; + break; + case 5: + this.minute = parseInt(parserArray[j], 10) + minuteDifference; + break; + case 6: + this.second = parseInt(parserArray[j], 10); + break; + default: + throw new Error("Wrong input string for convertion"); + } + } + //endregion + + //region Get final date + if (isUTC === false) { + const tempDate = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond); + + this.year = tempDate.getUTCFullYear(); + this.month = tempDate.getUTCMonth(); + this.day = tempDate.getUTCDay(); + this.hour = tempDate.getUTCHours(); + this.minute = tempDate.getUTCMinutes(); + this.second = tempDate.getUTCSeconds(); + this.millisecond = tempDate.getUTCMilliseconds(); + } + //endregion + } + //********************************************************************************** + /** + * Function converting ASN.1 internal class into JavaScript string + * @returns {string} + */ + toString() { + const outputArray = []; + + outputArray.push((0, _pvutils.padNumber)(this.year, 4)); + outputArray.push((0, _pvutils.padNumber)(this.month, 2)); + outputArray.push((0, _pvutils.padNumber)(this.day, 2)); + outputArray.push((0, _pvutils.padNumber)(this.hour, 2)); + outputArray.push((0, _pvutils.padNumber)(this.minute, 2)); + outputArray.push((0, _pvutils.padNumber)(this.second, 2)); + if (this.millisecond !== 0) { + outputArray.push("."); + outputArray.push((0, _pvutils.padNumber)(this.millisecond, 3)); + } + outputArray.push("Z"); + + return outputArray.join(""); + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "GeneralizedTime"; + } + //********************************************************************************** + /** + * Convertion for the block to JSON object + * @returns {Object} + */ + toJSON() { + let object = {}; + + //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object + try { + object = super.toJSON(); + } catch (ex) {} + //endregion + + object.year = this.year; + object.month = this.month; + object.day = this.day; + object.hour = this.hour; + object.minute = this.minute; + object.second = this.second; + object.millisecond = this.millisecond; + + return object; + } + //********************************************************************************** +} +exports.GeneralizedTime = GeneralizedTime; //************************************************************************************** +/** + * @extends Utf8String + */ + +class DATE extends Utf8String { + //********************************************************************************** + /** + * Constructor for "DATE" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) { + super(parameters); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 31; // DATE + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "DATE"; + } + //********************************************************************************** +} +exports.DATE = DATE; //************************************************************************************** +/** + * @extends Utf8String + */ + +class TimeOfDay extends Utf8String { + //********************************************************************************** + /** + * Constructor for "TimeOfDay" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) { + super(parameters); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 32; // TimeOfDay + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "TimeOfDay"; + } + //********************************************************************************** +} +exports.TimeOfDay = TimeOfDay; //************************************************************************************** +/** + * @extends Utf8String + */ + +class DateTime extends Utf8String { + //********************************************************************************** + /** + * Constructor for "DateTime" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) { + super(parameters); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 33; // DateTime + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "DateTime"; + } + //********************************************************************************** +} +exports.DateTime = DateTime; //************************************************************************************** +/** + * @extends Utf8String + */ + +class Duration extends Utf8String { + //********************************************************************************** + /** + * Constructor for "Duration" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) { + super(parameters); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 34; // Duration + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "Duration"; + } + //********************************************************************************** +} +exports.Duration = Duration; //************************************************************************************** +/** + * @extends Utf8String + */ + +class TIME extends Utf8String { + //********************************************************************************** + /** + * Constructor for "Time" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) { + super(parameters); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 14; // Time + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() { + return "TIME"; + } + //********************************************************************************** +} +exports.TIME = TIME; //************************************************************************************** +//endregion +//************************************************************************************** +//region Declaration of special ASN.1 schema type Choice +//************************************************************************************** + +class Choice { + //********************************************************************************** + /** + * Constructor for "Choice" class + * @param {Object} [parameters={}] + * @property {Array} [value] Array of ASN.1 types for make a choice from + * @property {boolean} [optional] + */ + constructor(parameters = {}) { + this.value = (0, _pvutils.getParametersValue)(parameters, "value", []); + this.optional = (0, _pvutils.getParametersValue)(parameters, "optional", false); + } + //********************************************************************************** +} +exports.Choice = Choice; //************************************************************************************** +//endregion +//************************************************************************************** +//region Declaration of special ASN.1 schema type Any +//************************************************************************************** + +class Any { + //********************************************************************************** + /** + * Constructor for "Any" class + * @param {Object} [parameters={}] + * @property {string} [name] + * @property {boolean} [optional] + */ + constructor(parameters = {}) { + this.name = (0, _pvutils.getParametersValue)(parameters, "name", ""); + this.optional = (0, _pvutils.getParametersValue)(parameters, "optional", false); + } + //********************************************************************************** +} +exports.Any = Any; //************************************************************************************** +//endregion +//************************************************************************************** +//region Declaration of special ASN.1 schema type Repeated +//************************************************************************************** + +class Repeated { + //********************************************************************************** + /** + * Constructor for "Repeated" class + * @param {Object} [parameters={}] + * @property {string} [name] + * @property {boolean} [optional] + */ + constructor(parameters = {}) { + this.name = (0, _pvutils.getParametersValue)(parameters, "name", ""); + this.optional = (0, _pvutils.getParametersValue)(parameters, "optional", false); + this.value = (0, _pvutils.getParametersValue)(parameters, "value", new Any()); + this.local = (0, _pvutils.getParametersValue)(parameters, "local", false); // Could local or global array to store elements + } + //********************************************************************************** +} +exports.Repeated = Repeated; //************************************************************************************** +//endregion +//************************************************************************************** +//region Declaration of special ASN.1 schema type RawData +//************************************************************************************** +/** + * @description Special class providing ability to have "toBER/fromBER" for raw ArrayBuffer + */ + +class RawData { + //********************************************************************************** + /** + * Constructor for "Repeated" class + * @param {Object} [parameters={}] + * @property {string} [name] + * @property {boolean} [optional] + */ + constructor(parameters = {}) { + this.data = (0, _pvutils.getParametersValue)(parameters, "data", new ArrayBuffer(0)); + } + //********************************************************************************** + /** + * Base function for converting block from BER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {number} Offset after least decoded byte + */ + fromBER(inputBuffer, inputOffset, inputLength) { + this.data = inputBuffer.slice(inputOffset, inputLength); + return inputOffset + inputLength; + } + //********************************************************************************** + /** + * Encoding of current ASN.1 block into ASN.1 encoded array (BER rules) + * @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes + * @returns {ArrayBuffer} + */ + toBER(sizeOnly = false) { + return this.data; + } + //********************************************************************************** +} +exports.RawData = RawData; //************************************************************************************** +//endregion +//************************************************************************************** +//region Major ASN.1 BER decoding function +//************************************************************************************** +/** + * Internal library function for decoding ASN.1 BER + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {{offset: number, result: Object}} + */ + +function LocalFromBER(inputBuffer, inputOffset, inputLength) { + const incomingOffset = inputOffset; // Need to store initial offset since "inputOffset" is changing in the function + + //region Local function changing a type for ASN.1 classes + function localChangeType(inputObject, newType) { + if (inputObject instanceof newType) return inputObject; + + const newObject = new newType(); + newObject.idBlock = inputObject.idBlock; + newObject.lenBlock = inputObject.lenBlock; + newObject.warnings = inputObject.warnings; + //noinspection JSCheckFunctionSignatures + newObject.valueBeforeDecode = inputObject.valueBeforeDecode.slice(0); + + return newObject; + } + //endregion + + //region Create a basic ASN.1 type since we need to return errors and warnings from the function + let returnObject = new BaseBlock({}, Object); + //endregion + + //region Basic check for parameters + if ((0, _pvutils.checkBufferParams)(new LocalBaseBlock(), inputBuffer, inputOffset, inputLength) === false) { + returnObject.error = "Wrong input parameters"; + return { + offset: -1, + result: returnObject + }; + } + //endregion + + //region Getting Uint8Array from ArrayBuffer + const intBuffer = new Uint8Array(inputBuffer, inputOffset, inputLength); + //endregion + + //region Initial checks + if (intBuffer.length === 0) { + this.error = "Zero buffer length"; + return { + offset: -1, + result: returnObject + }; + } + //endregion + + //region Decode indentifcation block of ASN.1 BER structure + let resultOffset = returnObject.idBlock.fromBER(inputBuffer, inputOffset, inputLength); + returnObject.warnings.concat(returnObject.idBlock.warnings); + if (resultOffset === -1) { + returnObject.error = returnObject.idBlock.error; + return { + offset: -1, + result: returnObject + }; + } + + inputOffset = resultOffset; + inputLength -= returnObject.idBlock.blockLength; + //endregion + + //region Decode length block of ASN.1 BER structure + resultOffset = returnObject.lenBlock.fromBER(inputBuffer, inputOffset, inputLength); + returnObject.warnings.concat(returnObject.lenBlock.warnings); + if (resultOffset === -1) { + returnObject.error = returnObject.lenBlock.error; + return { + offset: -1, + result: returnObject + }; + } + + inputOffset = resultOffset; + inputLength -= returnObject.lenBlock.blockLength; + //endregion + + //region Check for usign indefinite length form in encoding for primitive types + if (returnObject.idBlock.isConstructed === false && returnObject.lenBlock.isIndefiniteForm === true) { + returnObject.error = "Indefinite length form used for primitive encoding form"; + return { + offset: -1, + result: returnObject + }; + } + //endregion + + //region Switch ASN.1 block type + let newASN1Type = BaseBlock; + + switch (returnObject.idBlock.tagClass) { + //region UNIVERSAL + case 1: + //region Check for reserved tag numbers + if (returnObject.idBlock.tagNumber >= 37 && returnObject.idBlock.isHexOnly === false) { + returnObject.error = "UNIVERSAL 37 and upper tags are reserved by ASN.1 standard"; + return { + offset: -1, + result: returnObject + }; + } + //endregion + + switch (returnObject.idBlock.tagNumber) { + //region EndOfContent type + case 0: + //region Check for EndOfContent type + if (returnObject.idBlock.isConstructed === true && returnObject.lenBlock.length > 0) { + returnObject.error = "Type [UNIVERSAL 0] is reserved"; + return { + offset: -1, + result: returnObject + }; + } + //endregion + + newASN1Type = EndOfContent; + + break; + //endregion + //region Boolean type + case 1: + newASN1Type = Boolean; + break; + //endregion + //region Integer type + case 2: + newASN1Type = Integer; + break; + //endregion + //region BitString type + case 3: + newASN1Type = BitString; + break; + //endregion + //region OctetString type + case 4: + newASN1Type = OctetString; + break; + //endregion + //region Null type + case 5: + newASN1Type = Null; + break; + //endregion + //region OBJECT IDENTIFIER type + case 6: + newASN1Type = ObjectIdentifier; + break; + //endregion + //region Enumerated type + case 10: + newASN1Type = Enumerated; + break; + //endregion + //region Utf8String type + case 12: + newASN1Type = Utf8String; + break; + //endregion + //region Time type + case 14: + newASN1Type = TIME; + break; + //endregion + //region ASN.1 reserved type + case 15: + returnObject.error = "[UNIVERSAL 15] is reserved by ASN.1 standard"; + return { + offset: -1, + result: returnObject + }; + //endregion + //region Sequence type + case 16: + newASN1Type = Sequence; + break; + //endregion + //region Set type + case 17: + newASN1Type = Set; + break; + //endregion + //region NumericString type + case 18: + newASN1Type = NumericString; + break; + //endregion + //region PrintableString type + case 19: + newASN1Type = PrintableString; + break; + //endregion + //region TeletexString type + case 20: + newASN1Type = TeletexString; + break; + //endregion + //region VideotexString type + case 21: + newASN1Type = VideotexString; + break; + //endregion + //region IA5String type + case 22: + newASN1Type = IA5String; + break; + //endregion + //region UTCTime type + case 23: + newASN1Type = UTCTime; + break; + //endregion + //region GeneralizedTime type + case 24: + newASN1Type = GeneralizedTime; + break; + //endregion + //region GraphicString type + case 25: + newASN1Type = GraphicString; + break; + //endregion + //region VisibleString type + case 26: + newASN1Type = VisibleString; + break; + //endregion + //region GeneralString type + case 27: + newASN1Type = GeneralString; + break; + //endregion + //region UniversalString type + case 28: + newASN1Type = UniversalString; + break; + //endregion + //region CharacterString type + case 29: + newASN1Type = CharacterString; + break; + //endregion + //region BmpString type + case 30: + newASN1Type = BmpString; + break; + //endregion + //region DATE type + case 31: + newASN1Type = DATE; + break; + //endregion + //region TimeOfDay type + case 32: + newASN1Type = TimeOfDay; + break; + //endregion + //region Date-Time type + case 33: + newASN1Type = DateTime; + break; + //endregion + //region Duration type + case 34: + newASN1Type = Duration; + break; + //endregion + //region default + default: + { + let newObject; + + if (returnObject.idBlock.isConstructed === true) newObject = new Constructed();else newObject = new Primitive(); + + newObject.idBlock = returnObject.idBlock; + newObject.lenBlock = returnObject.lenBlock; + newObject.warnings = returnObject.warnings; + + returnObject = newObject; + + resultOffset = returnObject.fromBER(inputBuffer, inputOffset, inputLength); + } + //endregion + } + break; + //endregion + //region All other tag classes + case 2: // APPLICATION + case 3: // CONTEXT-SPECIFIC + case 4: // PRIVATE + default: + { + if (returnObject.idBlock.isConstructed === true) newASN1Type = Constructed;else newASN1Type = Primitive; + } + //endregion + } + //endregion + + //region Change type and perform BER decoding + returnObject = localChangeType(returnObject, newASN1Type); + resultOffset = returnObject.fromBER(inputBuffer, inputOffset, returnObject.lenBlock.isIndefiniteForm === true ? inputLength : returnObject.lenBlock.length); + //endregion + + //region Coping incoming buffer for entire ASN.1 block + returnObject.valueBeforeDecode = inputBuffer.slice(incomingOffset, incomingOffset + returnObject.blockLength); + //endregion + + return { + offset: resultOffset, + result: returnObject + }; +} +//************************************************************************************** +/** + * Major function for decoding ASN.1 BER array into internal library structuries + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array of bytes + */ +function fromBER(inputBuffer) { + if (inputBuffer.byteLength === 0) { + const result = new BaseBlock({}, Object); + result.error = "Input buffer has zero length"; + + return { + offset: -1, + result + }; + } + + return LocalFromBER(inputBuffer, 0, inputBuffer.byteLength); +} +//************************************************************************************** +//endregion +//************************************************************************************** +//region Major scheme verification function +//************************************************************************************** +/** + * Compare of two ASN.1 object trees + * @param {!Object} root Root of input ASN.1 object tree + * @param {!Object} inputData Input ASN.1 object tree + * @param {!Object} inputSchema Input ASN.1 schema to compare with + * @return {{verified: boolean}|{verified:boolean, result: Object}} + */ +function compareSchema(root, inputData, inputSchema) { + //region Special case for Choice schema element type + if (inputSchema instanceof Choice) { + const choiceResult = false; + + for (let j = 0; j < inputSchema.value.length; j++) { + const result = compareSchema(root, inputData, inputSchema.value[j]); + if (result.verified === true) { + return { + verified: true, + result: root + }; + } + } + + if (choiceResult === false) { + const _result = { + verified: false, + result: { + error: "Wrong values for Choice type" + } + }; + + if (inputSchema.hasOwnProperty("name")) _result.name = inputSchema.name; + + return _result; + } + } + //endregion + + //region Special case for Any schema element type + if (inputSchema instanceof Any) { + //region Add named component of ASN.1 schema + if (inputSchema.hasOwnProperty("name")) root[inputSchema.name] = inputData; + //endregion + + return { + verified: true, + result: root + }; + } + //endregion + + //region Initial check + if (root instanceof Object === false) { + return { + verified: false, + result: { error: "Wrong root object" } + }; + } + + if (inputData instanceof Object === false) { + return { + verified: false, + result: { error: "Wrong ASN.1 data" } + }; + } + + if (inputSchema instanceof Object === false) { + return { + verified: false, + result: { error: "Wrong ASN.1 schema" } + }; + } + + if ("idBlock" in inputSchema === false) { + return { + verified: false, + result: { error: "Wrong ASN.1 schema" } + }; + } + //endregion + + //region Comparing idBlock properties in ASN.1 data and ASN.1 schema + //region Encode and decode ASN.1 schema idBlock + /// This encoding/decoding is neccessary because could be an errors in schema definition + if ("fromBER" in inputSchema.idBlock === false) { + return { + verified: false, + result: { error: "Wrong ASN.1 schema" } + }; + } + + if ("toBER" in inputSchema.idBlock === false) { + return { + verified: false, + result: { error: "Wrong ASN.1 schema" } + }; + } + + const encodedId = inputSchema.idBlock.toBER(false); + if (encodedId.byteLength === 0) { + return { + verified: false, + result: { error: "Error encoding idBlock for ASN.1 schema" } + }; + } + + const decodedOffset = inputSchema.idBlock.fromBER(encodedId, 0, encodedId.byteLength); + if (decodedOffset === -1) { + return { + verified: false, + result: { error: "Error decoding idBlock for ASN.1 schema" } + }; + } + //endregion + + //region tagClass + if (inputSchema.idBlock.hasOwnProperty("tagClass") === false) { + return { + verified: false, + result: { error: "Wrong ASN.1 schema" } + }; + } + + if (inputSchema.idBlock.tagClass !== inputData.idBlock.tagClass) { + return { + verified: false, + result: root + }; + } + //endregion + //region tagNumber + if (inputSchema.idBlock.hasOwnProperty("tagNumber") === false) { + return { + verified: false, + result: { error: "Wrong ASN.1 schema" } + }; + } + + if (inputSchema.idBlock.tagNumber !== inputData.idBlock.tagNumber) { + return { + verified: false, + result: root + }; + } + //endregion + //region isConstructed + if (inputSchema.idBlock.hasOwnProperty("isConstructed") === false) { + return { + verified: false, + result: { error: "Wrong ASN.1 schema" } + }; + } + + if (inputSchema.idBlock.isConstructed !== inputData.idBlock.isConstructed) { + return { + verified: false, + result: root + }; + } + //endregion + //region isHexOnly + if ("isHexOnly" in inputSchema.idBlock === false) // Since 'isHexOnly' is an inhirited property + { + return { + verified: false, + result: { error: "Wrong ASN.1 schema" } + }; + } + + if (inputSchema.idBlock.isHexOnly !== inputData.idBlock.isHexOnly) { + return { + verified: false, + result: root + }; + } + //endregion + //region valueHex + if (inputSchema.idBlock.isHexOnly === true) { + if ("valueHex" in inputSchema.idBlock === false) // Since 'valueHex' is an inhirited property + { + return { + verified: false, + result: { error: "Wrong ASN.1 schema" } + }; + } + + const schemaView = new Uint8Array(inputSchema.idBlock.valueHex); + const asn1View = new Uint8Array(inputData.idBlock.valueHex); + + if (schemaView.length !== asn1View.length) { + return { + verified: false, + result: root + }; + } + + for (let i = 0; i < schemaView.length; i++) { + if (schemaView[i] !== asn1View[1]) { + return { + verified: false, + result: root + }; + } + } + } + //endregion + //endregion + + //region Add named component of ASN.1 schema + if (inputSchema.hasOwnProperty("name")) { + inputSchema.name = inputSchema.name.replace(/^\s+|\s+$/g, ""); + if (inputSchema.name !== "") root[inputSchema.name] = inputData; + } + //endregion + + //region Getting next ASN.1 block for comparition + if (inputSchema.idBlock.isConstructed === true) { + let admission = 0; + let result = { verified: false }; + + let maxLength = inputSchema.valueBlock.value.length; + + if (maxLength > 0) { + if (inputSchema.valueBlock.value[0] instanceof Repeated) maxLength = inputData.valueBlock.value.length; + } + + //region Special case when constructive value has no elements + if (maxLength === 0) { + return { + verified: true, + result: root + }; + } + //endregion + + //region Special case when "inputData" has no values and "inputSchema" has all optional values + if (inputData.valueBlock.value.length === 0 && inputSchema.valueBlock.value.length !== 0) { + let _optional = true; + + for (let i = 0; i < inputSchema.valueBlock.value.length; i++) _optional = _optional && (inputSchema.valueBlock.value[i].optional || false); + + if (_optional === true) { + return { + verified: true, + result: root + }; + } + + //region Delete early added name of block + if (inputSchema.hasOwnProperty("name")) { + inputSchema.name = inputSchema.name.replace(/^\s+|\s+$/g, ""); + if (inputSchema.name !== "") delete root[inputSchema.name]; + } + //endregion + + root.error = "Inconsistent object length"; + + return { + verified: false, + result: root + }; + } + //endregion + + for (let i = 0; i < maxLength; i++) { + //region Special case when there is an "optional" element of ASN.1 schema at the end + if (i - admission >= inputData.valueBlock.value.length) { + if (inputSchema.valueBlock.value[i].optional === false) { + const _result = { + verified: false, + result: root + }; + + root.error = "Inconsistent length between ASN.1 data and schema"; + + //region Delete early added name of block + if (inputSchema.hasOwnProperty("name")) { + inputSchema.name = inputSchema.name.replace(/^\s+|\s+$/g, ""); + if (inputSchema.name !== "") { + delete root[inputSchema.name]; + _result.name = inputSchema.name; + } + } + //endregion + + return _result; + } + } + //endregion + else { + //region Special case for Repeated type of ASN.1 schema element + if (inputSchema.valueBlock.value[0] instanceof Repeated) { + result = compareSchema(root, inputData.valueBlock.value[i], inputSchema.valueBlock.value[0].value); + if (result.verified === false) { + if (inputSchema.valueBlock.value[0].optional === true) admission++;else { + //region Delete early added name of block + if (inputSchema.hasOwnProperty("name")) { + inputSchema.name = inputSchema.name.replace(/^\s+|\s+$/g, ""); + if (inputSchema.name !== "") delete root[inputSchema.name]; + } + //endregion + + return result; + } + } + + if ("name" in inputSchema.valueBlock.value[0] && inputSchema.valueBlock.value[0].name.length > 0) { + let arrayRoot = {}; + + if ("local" in inputSchema.valueBlock.value[0] && inputSchema.valueBlock.value[0].local === true) arrayRoot = inputData;else arrayRoot = root; + + if (typeof arrayRoot[inputSchema.valueBlock.value[0].name] === "undefined") arrayRoot[inputSchema.valueBlock.value[0].name] = []; + + arrayRoot[inputSchema.valueBlock.value[0].name].push(inputData.valueBlock.value[i]); + } + } + //endregion + else { + result = compareSchema(root, inputData.valueBlock.value[i - admission], inputSchema.valueBlock.value[i]); + if (result.verified === false) { + if (inputSchema.valueBlock.value[i].optional === true) admission++;else { + //region Delete early added name of block + if (inputSchema.hasOwnProperty("name")) { + inputSchema.name = inputSchema.name.replace(/^\s+|\s+$/g, ""); + if (inputSchema.name !== "") delete root[inputSchema.name]; + } + //endregion + + return result; + } + } + } + } + } + + if (result.verified === false) // The situation may take place if last element is "optional" and verification failed + { + const _result = { + verified: false, + result: root + }; + + //region Delete early added name of block + if (inputSchema.hasOwnProperty("name")) { + inputSchema.name = inputSchema.name.replace(/^\s+|\s+$/g, ""); + if (inputSchema.name !== "") { + delete root[inputSchema.name]; + _result.name = inputSchema.name; + } + } + //endregion + + return _result; + } + + return { + verified: true, + result: root + }; + } + //endregion + //region Ability to parse internal value for primitive-encoded value (value of OctetString, for example) + if ("primitiveSchema" in inputSchema && "valueHex" in inputData.valueBlock) { + //region Decoding of raw ASN.1 data + const asn1 = fromBER(inputData.valueBlock.valueHex); + if (asn1.offset === -1) { + const _result = { + verified: false, + result: asn1.result + }; + + //region Delete early added name of block + if (inputSchema.hasOwnProperty("name")) { + inputSchema.name = inputSchema.name.replace(/^\s+|\s+$/g, ""); + if (inputSchema.name !== "") { + delete root[inputSchema.name]; + _result.name = inputSchema.name; + } + } + //endregion + + return _result; + } + //endregion + + return compareSchema(root, asn1.result, inputSchema.primitiveSchema); + } + + return { + verified: true, + result: root + }; + //endregion +} +//************************************************************************************** +//noinspection JSUnusedGlobalSymbols +/** + * ASN.1 schema verification for ArrayBuffer data + * @param {!ArrayBuffer} inputBuffer Input BER-encoded ASN.1 data + * @param {!Object} inputSchema Input ASN.1 schema to verify against to + * @return {{verified: boolean}|{verified:boolean, result: Object}} + */ +function verifySchema(inputBuffer, inputSchema) { + //region Initial check + if (inputSchema instanceof Object === false) { + return { + verified: false, + result: { error: "Wrong ASN.1 schema type" } + }; + } + //endregion + + //region Decoding of raw ASN.1 data + const asn1 = fromBER(inputBuffer); + if (asn1.offset === -1) { + return { + verified: false, + result: asn1.result + }; + } + //endregion + + //region Compare ASN.1 struct with input schema + return compareSchema(asn1.result, asn1.result, inputSchema); + //endregion +} +//************************************************************************************** +//endregion +//************************************************************************************** +//region Major function converting JSON to ASN.1 objects +//************************************************************************************** +//noinspection JSUnusedGlobalSymbols +/** + * Converting from JSON to ASN.1 objects + * @param {string|Object} json JSON string or object to convert to ASN.1 objects + */ +function fromJSON(json) {} +// TODO Implement + +//************************************************************************************** +//endregion +//************************************************************************************** + +},{"pvutils":113}],113:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.getUTCDate = getUTCDate; +exports.getParametersValue = getParametersValue; +exports.bufferToHexCodes = bufferToHexCodes; +exports.checkBufferParams = checkBufferParams; +exports.utilFromBase = utilFromBase; +exports.utilToBase = utilToBase; +exports.utilConcatBuf = utilConcatBuf; +exports.utilConcatView = utilConcatView; +exports.utilDecodeTC = utilDecodeTC; +exports.utilEncodeTC = utilEncodeTC; +exports.isEqualBuffer = isEqualBuffer; +exports.padNumber = padNumber; +exports.toBase64 = toBase64; +exports.fromBase64 = fromBase64; +exports.arrayBufferToString = arrayBufferToString; +exports.stringToArrayBuffer = stringToArrayBuffer; +exports.nearestPowerOf2 = nearestPowerOf2; +exports.clearProps = clearProps; +//************************************************************************************** +/** + * Making UTC date from local date + * @param {Date} date Date to convert from + * @returns {Date} + */ +function getUTCDate(date) { + // noinspection NestedFunctionCallJS, MagicNumberJS + return new Date(date.getTime() + date.getTimezoneOffset() * 60000); +} +//************************************************************************************** +// noinspection FunctionWithMultipleReturnPointsJS +/** + * Get value for input parameters, or set a default value + * @param {Object} parameters + * @param {string} name + * @param defaultValue + */ +function getParametersValue(parameters, name, defaultValue) { + // noinspection ConstantOnRightSideOfComparisonJS, NonBlockStatementBodyJS + if (parameters instanceof Object === false) return defaultValue; + + // noinspection NonBlockStatementBodyJS + if (name in parameters) return parameters[name]; + + return defaultValue; +} +//************************************************************************************** +/** + * Converts "ArrayBuffer" into a hexdecimal string + * @param {ArrayBuffer} inputBuffer + * @param {number} [inputOffset=0] + * @param {number} [inputLength=inputBuffer.byteLength] + * @param {boolean} [insertSpace=false] + * @returns {string} + */ +function bufferToHexCodes(inputBuffer, inputOffset = 0, inputLength = inputBuffer.byteLength - inputOffset, insertSpace = false) { + let result = ""; + + var _iteratorNormalCompletion = true; + var _didIteratorError = false; + var _iteratorError = undefined; + + try { + for (var _iterator = new Uint8Array(inputBuffer, inputOffset, inputLength)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { + const item = _step.value; + + // noinspection ChainedFunctionCallJS + const str = item.toString(16).toUpperCase(); + + // noinspection ConstantOnRightSideOfComparisonJS, NonBlockStatementBodyJS + if (str.length === 1) result += "0"; + + result += str; + + // noinspection NonBlockStatementBodyJS + if (insertSpace) result += " "; + } + } catch (err) { + _didIteratorError = true; + _iteratorError = err; + } finally { + try { + if (!_iteratorNormalCompletion && _iterator.return) { + _iterator.return(); + } + } finally { + if (_didIteratorError) { + throw _iteratorError; + } + } + } + + return result.trim(); +} +//************************************************************************************** +// noinspection JSValidateJSDoc, FunctionWithMultipleReturnPointsJS +/** + * Check input "ArrayBuffer" for common functions + * @param {LocalBaseBlock} baseBlock + * @param {ArrayBuffer} inputBuffer + * @param {number} inputOffset + * @param {number} inputLength + * @returns {boolean} + */ +function checkBufferParams(baseBlock, inputBuffer, inputOffset, inputLength) { + // noinspection ConstantOnRightSideOfComparisonJS + if (inputBuffer instanceof ArrayBuffer === false) { + // noinspection JSUndefinedPropertyAssignment + baseBlock.error = "Wrong parameter: inputBuffer must be \"ArrayBuffer\""; + return false; + } + + // noinspection ConstantOnRightSideOfComparisonJS + if (inputBuffer.byteLength === 0) { + // noinspection JSUndefinedPropertyAssignment + baseBlock.error = "Wrong parameter: inputBuffer has zero length"; + return false; + } + + // noinspection ConstantOnRightSideOfComparisonJS + if (inputOffset < 0) { + // noinspection JSUndefinedPropertyAssignment + baseBlock.error = "Wrong parameter: inputOffset less than zero"; + return false; + } + + // noinspection ConstantOnRightSideOfComparisonJS + if (inputLength < 0) { + // noinspection JSUndefinedPropertyAssignment + baseBlock.error = "Wrong parameter: inputLength less than zero"; + return false; + } + + // noinspection ConstantOnRightSideOfComparisonJS + if (inputBuffer.byteLength - inputOffset - inputLength < 0) { + // noinspection JSUndefinedPropertyAssignment + baseBlock.error = "End of input reached before message was fully decoded (inconsistent offset and length values)"; + return false; + } + + return true; +} +//************************************************************************************** +// noinspection FunctionWithMultipleReturnPointsJS +/** + * Convert number from 2^base to 2^10 + * @param {Uint8Array} inputBuffer + * @param {number} inputBase + * @returns {number} + */ +function utilFromBase(inputBuffer, inputBase) { + let result = 0; + + // noinspection ConstantOnRightSideOfComparisonJS, NonBlockStatementBodyJS + if (inputBuffer.length === 1) return inputBuffer[0]; + + // noinspection ConstantOnRightSideOfComparisonJS, NonBlockStatementBodyJS + for (let i = inputBuffer.length - 1; i >= 0; i--) result += inputBuffer[inputBuffer.length - 1 - i] * Math.pow(2, inputBase * i); + + return result; +} +//************************************************************************************** +// noinspection FunctionWithMultipleLoopsJS, FunctionWithMultipleReturnPointsJS +/** + * Convert number from 2^10 to 2^base + * @param {!number} value The number to convert + * @param {!number} base The base for 2^base + * @param {number} [reserved=0] Pre-defined number of bytes in output array (-1 = limited by function itself) + * @returns {ArrayBuffer} + */ +function utilToBase(value, base, reserved = -1) { + const internalReserved = reserved; + let internalValue = value; + + let result = 0; + let biggest = Math.pow(2, base); + + // noinspection ConstantOnRightSideOfComparisonJS + for (let i = 1; i < 8; i++) { + if (value < biggest) { + let retBuf; + + // noinspection ConstantOnRightSideOfComparisonJS + if (internalReserved < 0) { + retBuf = new ArrayBuffer(i); + result = i; + } else { + // noinspection NonBlockStatementBodyJS + if (internalReserved < i) return new ArrayBuffer(0); + + retBuf = new ArrayBuffer(internalReserved); + + result = internalReserved; + } + + const retView = new Uint8Array(retBuf); + + // noinspection ConstantOnRightSideOfComparisonJS + for (let j = i - 1; j >= 0; j--) { + const basis = Math.pow(2, j * base); + + retView[result - j - 1] = Math.floor(internalValue / basis); + internalValue -= retView[result - j - 1] * basis; + } + + return retBuf; + } + + biggest *= Math.pow(2, base); + } + + return new ArrayBuffer(0); +} +//************************************************************************************** +// noinspection FunctionWithMultipleLoopsJS +/** + * Concatenate two ArrayBuffers + * @param {...ArrayBuffer} buffers Set of ArrayBuffer + */ +function utilConcatBuf(...buffers) { + //region Initial variables + let outputLength = 0; + let prevLength = 0; + //endregion + + //region Calculate output length + + // noinspection NonBlockStatementBodyJS + var _iteratorNormalCompletion2 = true; + var _didIteratorError2 = false; + var _iteratorError2 = undefined; + + try { + for (var _iterator2 = buffers[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { + const buffer = _step2.value; + + outputLength += buffer.byteLength; + } //endregion + } catch (err) { + _didIteratorError2 = true; + _iteratorError2 = err; + } finally { + try { + if (!_iteratorNormalCompletion2 && _iterator2.return) { + _iterator2.return(); + } + } finally { + if (_didIteratorError2) { + throw _iteratorError2; + } + } + } + + const retBuf = new ArrayBuffer(outputLength); + const retView = new Uint8Array(retBuf); + + var _iteratorNormalCompletion3 = true; + var _didIteratorError3 = false; + var _iteratorError3 = undefined; + + try { + for (var _iterator3 = buffers[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) { + const buffer = _step3.value; + + // noinspection NestedFunctionCallJS + retView.set(new Uint8Array(buffer), prevLength); + prevLength += buffer.byteLength; + } + } catch (err) { + _didIteratorError3 = true; + _iteratorError3 = err; + } finally { + try { + if (!_iteratorNormalCompletion3 && _iterator3.return) { + _iterator3.return(); + } + } finally { + if (_didIteratorError3) { + throw _iteratorError3; + } + } + } + + return retBuf; +} +//************************************************************************************** +// noinspection FunctionWithMultipleLoopsJS +/** + * Concatenate two Uint8Array + * @param {...Uint8Array} views Set of Uint8Array + */ +function utilConcatView(...views) { + //region Initial variables + let outputLength = 0; + let prevLength = 0; + //endregion + + //region Calculate output length + // noinspection NonBlockStatementBodyJS + var _iteratorNormalCompletion4 = true; + var _didIteratorError4 = false; + var _iteratorError4 = undefined; + + try { + for (var _iterator4 = views[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) { + const view = _step4.value; + + outputLength += view.length; + } //endregion + } catch (err) { + _didIteratorError4 = true; + _iteratorError4 = err; + } finally { + try { + if (!_iteratorNormalCompletion4 && _iterator4.return) { + _iterator4.return(); + } + } finally { + if (_didIteratorError4) { + throw _iteratorError4; + } + } + } + + const retBuf = new ArrayBuffer(outputLength); + const retView = new Uint8Array(retBuf); + + var _iteratorNormalCompletion5 = true; + var _didIteratorError5 = false; + var _iteratorError5 = undefined; + + try { + for (var _iterator5 = views[Symbol.iterator](), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) { + const view = _step5.value; + + retView.set(view, prevLength); + prevLength += view.length; + } + } catch (err) { + _didIteratorError5 = true; + _iteratorError5 = err; + } finally { + try { + if (!_iteratorNormalCompletion5 && _iterator5.return) { + _iterator5.return(); + } + } finally { + if (_didIteratorError5) { + throw _iteratorError5; + } + } + } + + return retView; +} +//************************************************************************************** +// noinspection FunctionWithMultipleLoopsJS +/** + * Decoding of "two complement" values + * The function must be called in scope of instance of "hexBlock" class ("valueHex" and "warnings" properties must be present) + * @returns {number} + */ +function utilDecodeTC() { + const buf = new Uint8Array(this.valueHex); + + // noinspection ConstantOnRightSideOfComparisonJS + if (this.valueHex.byteLength >= 2) { + //noinspection JSBitwiseOperatorUsage, ConstantOnRightSideOfComparisonJS, LocalVariableNamingConventionJS, MagicNumberJS, NonShortCircuitBooleanExpressionJS + const condition1 = buf[0] === 0xFF && buf[1] & 0x80; + // noinspection ConstantOnRightSideOfComparisonJS, LocalVariableNamingConventionJS, MagicNumberJS, NonShortCircuitBooleanExpressionJS + const condition2 = buf[0] === 0x00 && (buf[1] & 0x80) === 0x00; + + // noinspection NonBlockStatementBodyJS + if (condition1 || condition2) this.warnings.push("Needlessly long format"); + } + + //region Create big part of the integer + const bigIntBuffer = new ArrayBuffer(this.valueHex.byteLength); + const bigIntView = new Uint8Array(bigIntBuffer); + // noinspection NonBlockStatementBodyJS + for (let i = 0; i < this.valueHex.byteLength; i++) bigIntView[i] = 0; + + // noinspection MagicNumberJS, NonShortCircuitBooleanExpressionJS + bigIntView[0] = buf[0] & 0x80; // mask only the biggest bit + + const bigInt = utilFromBase(bigIntView, 8); + //endregion + + //region Create small part of the integer + const smallIntBuffer = new ArrayBuffer(this.valueHex.byteLength); + const smallIntView = new Uint8Array(smallIntBuffer); + // noinspection NonBlockStatementBodyJS + for (let j = 0; j < this.valueHex.byteLength; j++) smallIntView[j] = buf[j]; + + // noinspection MagicNumberJS + smallIntView[0] &= 0x7F; // mask biggest bit + + const smallInt = utilFromBase(smallIntView, 8); + //endregion + + return smallInt - bigInt; +} +//************************************************************************************** +// noinspection FunctionWithMultipleLoopsJS, FunctionWithMultipleReturnPointsJS +/** + * Encode integer value to "two complement" format + * @param {number} value Value to encode + * @returns {ArrayBuffer} + */ +function utilEncodeTC(value) { + // noinspection ConstantOnRightSideOfComparisonJS, ConditionalExpressionJS + const modValue = value < 0 ? value * -1 : value; + let bigInt = 128; + + // noinspection ConstantOnRightSideOfComparisonJS + for (let i = 1; i < 8; i++) { + if (modValue <= bigInt) { + // noinspection ConstantOnRightSideOfComparisonJS + if (value < 0) { + const smallInt = bigInt - modValue; + + const retBuf = utilToBase(smallInt, 8, i); + const retView = new Uint8Array(retBuf); + + // noinspection MagicNumberJS + retView[0] |= 0x80; + + return retBuf; + } + + let retBuf = utilToBase(modValue, 8, i); + let retView = new Uint8Array(retBuf); + + //noinspection JSBitwiseOperatorUsage, MagicNumberJS, NonShortCircuitBooleanExpressionJS + if (retView[0] & 0x80) { + //noinspection JSCheckFunctionSignatures + const tempBuf = retBuf.slice(0); + const tempView = new Uint8Array(tempBuf); + + retBuf = new ArrayBuffer(retBuf.byteLength + 1); + // noinspection ReuseOfLocalVariableJS + retView = new Uint8Array(retBuf); + + // noinspection NonBlockStatementBodyJS + for (let k = 0; k < tempBuf.byteLength; k++) retView[k + 1] = tempView[k]; + + // noinspection MagicNumberJS + retView[0] = 0x00; + } + + return retBuf; + } + + bigInt *= Math.pow(2, 8); + } + + return new ArrayBuffer(0); +} +//************************************************************************************** +// noinspection FunctionWithMultipleReturnPointsJS, ParameterNamingConventionJS +/** + * Compare two array buffers + * @param {!ArrayBuffer} inputBuffer1 + * @param {!ArrayBuffer} inputBuffer2 + * @returns {boolean} + */ +function isEqualBuffer(inputBuffer1, inputBuffer2) { + // noinspection NonBlockStatementBodyJS + if (inputBuffer1.byteLength !== inputBuffer2.byteLength) return false; + + // noinspection LocalVariableNamingConventionJS + const view1 = new Uint8Array(inputBuffer1); + // noinspection LocalVariableNamingConventionJS + const view2 = new Uint8Array(inputBuffer2); + + for (let i = 0; i < view1.length; i++) { + // noinspection NonBlockStatementBodyJS + if (view1[i] !== view2[i]) return false; + } + + return true; +} +//************************************************************************************** +// noinspection FunctionWithMultipleReturnPointsJS +/** + * Pad input number with leade "0" if needed + * @returns {string} + * @param {number} inputNumber + * @param {number} fullLength + */ +function padNumber(inputNumber, fullLength) { + const str = inputNumber.toString(10); + + // noinspection NonBlockStatementBodyJS + if (fullLength < str.length) return ""; + + const dif = fullLength - str.length; + + const padding = new Array(dif); + // noinspection NonBlockStatementBodyJS + for (let i = 0; i < dif; i++) padding[i] = "0"; + + const paddingString = padding.join(""); + + return paddingString.concat(str); +} +//************************************************************************************** +const base64Template = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; +const base64UrlTemplate = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_="; +//************************************************************************************** +// noinspection FunctionWithMultipleLoopsJS, OverlyComplexFunctionJS, FunctionTooLongJS, FunctionNamingConventionJS +/** + * Encode string into BASE64 (or "base64url") + * @param {string} input + * @param {boolean} useUrlTemplate If "true" then output would be encoded using "base64url" + * @param {boolean} skipPadding Skip BASE-64 padding or not + * @param {boolean} skipLeadingZeros Skip leading zeros in input data or not + * @returns {string} + */ +function toBase64(input, useUrlTemplate = false, skipPadding = false, skipLeadingZeros = false) { + let i = 0; + + // noinspection LocalVariableNamingConventionJS + let flag1 = 0; + // noinspection LocalVariableNamingConventionJS + let flag2 = 0; + + let output = ""; + + // noinspection ConditionalExpressionJS + const template = useUrlTemplate ? base64UrlTemplate : base64Template; + + if (skipLeadingZeros) { + let nonZeroPosition = 0; + + for (let i = 0; i < input.length; i++) { + // noinspection ConstantOnRightSideOfComparisonJS + if (input.charCodeAt(i) !== 0) { + nonZeroPosition = i; + // noinspection BreakStatementJS + break; + } + } + + // noinspection AssignmentToFunctionParameterJS + input = input.slice(nonZeroPosition); + } + + while (i < input.length) { + // noinspection LocalVariableNamingConventionJS, IncrementDecrementResultUsedJS + const chr1 = input.charCodeAt(i++); + // noinspection NonBlockStatementBodyJS + if (i >= input.length) flag1 = 1; + // noinspection LocalVariableNamingConventionJS, IncrementDecrementResultUsedJS + const chr2 = input.charCodeAt(i++); + // noinspection NonBlockStatementBodyJS + if (i >= input.length) flag2 = 1; + // noinspection LocalVariableNamingConventionJS, IncrementDecrementResultUsedJS + const chr3 = input.charCodeAt(i++); + + // noinspection LocalVariableNamingConventionJS + const enc1 = chr1 >> 2; + // noinspection LocalVariableNamingConventionJS, MagicNumberJS, NonShortCircuitBooleanExpressionJS + const enc2 = (chr1 & 0x03) << 4 | chr2 >> 4; + // noinspection LocalVariableNamingConventionJS, MagicNumberJS, NonShortCircuitBooleanExpressionJS + let enc3 = (chr2 & 0x0F) << 2 | chr3 >> 6; + // noinspection LocalVariableNamingConventionJS, MagicNumberJS, NonShortCircuitBooleanExpressionJS + let enc4 = chr3 & 0x3F; + + // noinspection ConstantOnRightSideOfComparisonJS + if (flag1 === 1) { + // noinspection NestedAssignmentJS, AssignmentResultUsedJS, MagicNumberJS + enc3 = enc4 = 64; + } else { + // noinspection ConstantOnRightSideOfComparisonJS + if (flag2 === 1) { + // noinspection MagicNumberJS + enc4 = 64; + } + } + + // noinspection NonBlockStatementBodyJS + if (skipPadding) { + // noinspection ConstantOnRightSideOfComparisonJS, NonBlockStatementBodyJS, MagicNumberJS + if (enc3 === 64) output += `${template.charAt(enc1)}${template.charAt(enc2)}`;else { + // noinspection ConstantOnRightSideOfComparisonJS, NonBlockStatementBodyJS, MagicNumberJS + if (enc4 === 64) output += `${template.charAt(enc1)}${template.charAt(enc2)}${template.charAt(enc3)}`;else output += `${template.charAt(enc1)}${template.charAt(enc2)}${template.charAt(enc3)}${template.charAt(enc4)}`; + } + } else output += `${template.charAt(enc1)}${template.charAt(enc2)}${template.charAt(enc3)}${template.charAt(enc4)}`; + } + + return output; +} +//************************************************************************************** +// noinspection FunctionWithMoreThanThreeNegationsJS, FunctionWithMultipleLoopsJS, OverlyComplexFunctionJS, FunctionNamingConventionJS +/** + * Decode string from BASE64 (or "base64url") + * @param {string} input + * @param {boolean} [useUrlTemplate=false] If "true" then output would be encoded using "base64url" + * @param {boolean} [cutTailZeros=false] If "true" then cut tailing zeroz from function result + * @returns {string} + */ +function fromBase64(input, useUrlTemplate = false, cutTailZeros = false) { + // noinspection ConditionalExpressionJS + const template = useUrlTemplate ? base64UrlTemplate : base64Template; + + //region Aux functions + // noinspection FunctionWithMultipleReturnPointsJS, NestedFunctionJS + function indexof(toSearch) { + // noinspection ConstantOnRightSideOfComparisonJS, MagicNumberJS + for (let i = 0; i < 64; i++) { + // noinspection NonBlockStatementBodyJS + if (template.charAt(i) === toSearch) return i; + } + + // noinspection MagicNumberJS + return 64; + } + + // noinspection NestedFunctionJS + function test(incoming) { + // noinspection ConstantOnRightSideOfComparisonJS, ConditionalExpressionJS, MagicNumberJS + return incoming === 64 ? 0x00 : incoming; + } + //endregion + + let i = 0; + + let output = ""; + + while (i < input.length) { + // noinspection NestedFunctionCallJS, LocalVariableNamingConventionJS, IncrementDecrementResultUsedJS + const enc1 = indexof(input.charAt(i++)); + // noinspection NestedFunctionCallJS, LocalVariableNamingConventionJS, ConditionalExpressionJS, MagicNumberJS, IncrementDecrementResultUsedJS + const enc2 = i >= input.length ? 0x00 : indexof(input.charAt(i++)); + // noinspection NestedFunctionCallJS, LocalVariableNamingConventionJS, ConditionalExpressionJS, MagicNumberJS, IncrementDecrementResultUsedJS + const enc3 = i >= input.length ? 0x00 : indexof(input.charAt(i++)); + // noinspection NestedFunctionCallJS, LocalVariableNamingConventionJS, ConditionalExpressionJS, MagicNumberJS, IncrementDecrementResultUsedJS + const enc4 = i >= input.length ? 0x00 : indexof(input.charAt(i++)); + + // noinspection LocalVariableNamingConventionJS, NonShortCircuitBooleanExpressionJS + const chr1 = test(enc1) << 2 | test(enc2) >> 4; + // noinspection LocalVariableNamingConventionJS, MagicNumberJS, NonShortCircuitBooleanExpressionJS + const chr2 = (test(enc2) & 0x0F) << 4 | test(enc3) >> 2; + // noinspection LocalVariableNamingConventionJS, MagicNumberJS, NonShortCircuitBooleanExpressionJS + const chr3 = (test(enc3) & 0x03) << 6 | test(enc4); + + output += String.fromCharCode(chr1); + + // noinspection ConstantOnRightSideOfComparisonJS, NonBlockStatementBodyJS, MagicNumberJS + if (enc3 !== 64) output += String.fromCharCode(chr2); + + // noinspection ConstantOnRightSideOfComparisonJS, NonBlockStatementBodyJS, MagicNumberJS + if (enc4 !== 64) output += String.fromCharCode(chr3); + } + + if (cutTailZeros) { + const outputLength = output.length; + let nonZeroStart = -1; + + // noinspection ConstantOnRightSideOfComparisonJS + for (let i = outputLength - 1; i >= 0; i--) { + // noinspection ConstantOnRightSideOfComparisonJS + if (output.charCodeAt(i) !== 0) { + nonZeroStart = i; + // noinspection BreakStatementJS + break; + } + } + + // noinspection NonBlockStatementBodyJS, NegatedIfStatementJS + if (nonZeroStart !== -1) output = output.slice(0, nonZeroStart + 1);else output = ""; + } + + return output; +} +//************************************************************************************** +function arrayBufferToString(buffer) { + let resultString = ""; + const view = new Uint8Array(buffer); + + // noinspection NonBlockStatementBodyJS + var _iteratorNormalCompletion6 = true; + var _didIteratorError6 = false; + var _iteratorError6 = undefined; + + try { + for (var _iterator6 = view[Symbol.iterator](), _step6; !(_iteratorNormalCompletion6 = (_step6 = _iterator6.next()).done); _iteratorNormalCompletion6 = true) { + const element = _step6.value; + + resultString += String.fromCharCode(element); + } + } catch (err) { + _didIteratorError6 = true; + _iteratorError6 = err; + } finally { + try { + if (!_iteratorNormalCompletion6 && _iterator6.return) { + _iterator6.return(); + } + } finally { + if (_didIteratorError6) { + throw _iteratorError6; + } + } + } + + return resultString; +} +//************************************************************************************** +function stringToArrayBuffer(str) { + const stringLength = str.length; + + const resultBuffer = new ArrayBuffer(stringLength); + const resultView = new Uint8Array(resultBuffer); + + // noinspection NonBlockStatementBodyJS + for (let i = 0; i < stringLength; i++) resultView[i] = str.charCodeAt(i); + + return resultBuffer; +} +//************************************************************************************** +const log2 = Math.log(2); +//************************************************************************************** +// noinspection FunctionNamingConventionJS +/** + * Get nearest to input length power of 2 + * @param {number} length Current length of existing array + * @returns {number} + */ +function nearestPowerOf2(length) { + const base = Math.log(length) / log2; + + const floor = Math.floor(base); + const round = Math.round(base); + + // noinspection ConditionalExpressionJS + return floor === round ? floor : round; +} +//************************************************************************************** +/** + * Delete properties by name from specified object + * @param {Object} object Object to delete properties from + * @param {Array.} propsArray Array of properties names + */ +function clearProps(object, propsArray) { + var _iteratorNormalCompletion7 = true; + var _didIteratorError7 = false; + var _iteratorError7 = undefined; + + try { + for (var _iterator7 = propsArray[Symbol.iterator](), _step7; !(_iteratorNormalCompletion7 = (_step7 = _iterator7.next()).done); _iteratorNormalCompletion7 = true) { + const prop = _step7.value; + + delete object[prop]; + } + } catch (err) { + _didIteratorError7 = true; + _iteratorError7 = err; + } finally { + try { + if (!_iteratorNormalCompletion7 && _iterator7.return) { + _iterator7.return(); + } + } finally { + if (_didIteratorError7) { + throw _iteratorError7; + } + } + } +} +//************************************************************************************** + +},{}],114:[function(require,module,exports){ +// shim for using process in browser +var process = module.exports = {}; + +// cached from whatever global is present so that test runners that stub it +// don't break things. But we need to wrap it in a try catch in case it is +// wrapped in strict mode code which doesn't define any globals. It's inside a +// function because try/catches deoptimize in certain engines. + +var cachedSetTimeout; +var cachedClearTimeout; + +function defaultSetTimout() { + throw new Error('setTimeout has not been defined'); +} +function defaultClearTimeout () { + throw new Error('clearTimeout has not been defined'); +} +(function () { + try { + if (typeof setTimeout === 'function') { + cachedSetTimeout = setTimeout; + } else { + cachedSetTimeout = defaultSetTimout; + } + } catch (e) { + cachedSetTimeout = defaultSetTimout; + } + try { + if (typeof clearTimeout === 'function') { + cachedClearTimeout = clearTimeout; + } else { + cachedClearTimeout = defaultClearTimeout; + } + } catch (e) { + cachedClearTimeout = defaultClearTimeout; + } +} ()) +function runTimeout(fun) { + if (cachedSetTimeout === setTimeout) { + //normal enviroments in sane situations + return setTimeout(fun, 0); + } + // if setTimeout wasn't available but was latter defined + if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { + cachedSetTimeout = setTimeout; + return setTimeout(fun, 0); + } + try { + // when when somebody has screwed with setTimeout but no I.E. maddness + return cachedSetTimeout(fun, 0); + } catch(e){ + try { + // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally + return cachedSetTimeout.call(null, fun, 0); + } catch(e){ + // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error + return cachedSetTimeout.call(this, fun, 0); + } + } + + +} +function runClearTimeout(marker) { + if (cachedClearTimeout === clearTimeout) { + //normal enviroments in sane situations + return clearTimeout(marker); + } + // if clearTimeout wasn't available but was latter defined + if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) { + cachedClearTimeout = clearTimeout; + return clearTimeout(marker); + } + try { + // when when somebody has screwed with setTimeout but no I.E. maddness + return cachedClearTimeout(marker); + } catch (e){ + try { + // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally + return cachedClearTimeout.call(null, marker); + } catch (e){ + // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error. + // Some versions of I.E. have different rules for clearTimeout vs setTimeout + return cachedClearTimeout.call(this, marker); + } + } + + + +} +var queue = []; +var draining = false; +var currentQueue; +var queueIndex = -1; + +function cleanUpNextTick() { + if (!draining || !currentQueue) { + return; + } + draining = false; + if (currentQueue.length) { + queue = currentQueue.concat(queue); + } else { + queueIndex = -1; + } + if (queue.length) { + drainQueue(); + } +} + +function drainQueue() { + if (draining) { + return; + } + var timeout = runTimeout(cleanUpNextTick); + draining = true; + + var len = queue.length; + while(len) { + currentQueue = queue; + queue = []; + while (++queueIndex < len) { + if (currentQueue) { + currentQueue[queueIndex].run(); + } + } + queueIndex = -1; + len = queue.length; + } + currentQueue = null; + draining = false; + runClearTimeout(timeout); +} + +process.nextTick = function (fun) { + var args = new Array(arguments.length - 1); + if (arguments.length > 1) { + for (var i = 1; i < arguments.length; i++) { + args[i - 1] = arguments[i]; + } + } + queue.push(new Item(fun, args)); + if (queue.length === 1 && !draining) { + runTimeout(drainQueue); + } +}; + +// v8 likes predictible objects +function Item(fun, array) { + this.fun = fun; + this.array = array; +} +Item.prototype.run = function () { + this.fun.apply(null, this.array); +}; +process.title = 'browser'; +process.browser = true; +process.env = {}; +process.argv = []; +process.version = ''; // empty string to avoid regexp issues +process.versions = {}; + +function noop() {} + +process.on = noop; +process.addListener = noop; +process.once = noop; +process.off = noop; +process.removeListener = noop; +process.removeAllListeners = noop; +process.emit = noop; +process.prependListener = noop; +process.prependOnceListener = noop; + +process.listeners = function (name) { return [] } + +process.binding = function (name) { + throw new Error('process.binding is not supported'); +}; + +process.cwd = function () { return '/' }; +process.chdir = function (dir) { + throw new Error('process.chdir is not supported'); +}; +process.umask = function() { return 0; }; + +},{}],115:[function(require,module,exports){ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +const pkijs = require("pkijs"); // version 2.1.78 + +module.exports = { + pkijs, +}; + +},{"pkijs":111}]},{},[115])(115) +}); diff --git a/toolkit/components/certviewer/content/vendor/pvutils_bundle.js b/toolkit/components/certviewer/content/vendor/pvutils_bundle.js new file mode 100644 index 000000000000..4ecec5e22330 --- /dev/null +++ b/toolkit/components/certviewer/content/vendor/pvutils_bundle.js @@ -0,0 +1,791 @@ +(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.pvutils = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i= 0; i--) result += inputBuffer[inputBuffer.length - 1 - i] * Math.pow(2, inputBase * i); + + return result; +} +//************************************************************************************** +// noinspection FunctionWithMultipleLoopsJS, FunctionWithMultipleReturnPointsJS +/** + * Convert number from 2^10 to 2^base + * @param {!number} value The number to convert + * @param {!number} base The base for 2^base + * @param {number} [reserved=0] Pre-defined number of bytes in output array (-1 = limited by function itself) + * @returns {ArrayBuffer} + */ +function utilToBase(value, base, reserved = -1) { + const internalReserved = reserved; + let internalValue = value; + + let result = 0; + let biggest = Math.pow(2, base); + + // noinspection ConstantOnRightSideOfComparisonJS + for (let i = 1; i < 8; i++) { + if (value < biggest) { + let retBuf; + + // noinspection ConstantOnRightSideOfComparisonJS + if (internalReserved < 0) { + retBuf = new ArrayBuffer(i); + result = i; + } else { + // noinspection NonBlockStatementBodyJS + if (internalReserved < i) return new ArrayBuffer(0); + + retBuf = new ArrayBuffer(internalReserved); + + result = internalReserved; + } + + const retView = new Uint8Array(retBuf); + + // noinspection ConstantOnRightSideOfComparisonJS + for (let j = i - 1; j >= 0; j--) { + const basis = Math.pow(2, j * base); + + retView[result - j - 1] = Math.floor(internalValue / basis); + internalValue -= retView[result - j - 1] * basis; + } + + return retBuf; + } + + biggest *= Math.pow(2, base); + } + + return new ArrayBuffer(0); +} +//************************************************************************************** +// noinspection FunctionWithMultipleLoopsJS +/** + * Concatenate two ArrayBuffers + * @param {...ArrayBuffer} buffers Set of ArrayBuffer + */ +function utilConcatBuf(...buffers) { + //region Initial variables + let outputLength = 0; + let prevLength = 0; + //endregion + + //region Calculate output length + + // noinspection NonBlockStatementBodyJS + var _iteratorNormalCompletion2 = true; + var _didIteratorError2 = false; + var _iteratorError2 = undefined; + + try { + for (var _iterator2 = buffers[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { + const buffer = _step2.value; + + outputLength += buffer.byteLength; + } //endregion + } catch (err) { + _didIteratorError2 = true; + _iteratorError2 = err; + } finally { + try { + if (!_iteratorNormalCompletion2 && _iterator2.return) { + _iterator2.return(); + } + } finally { + if (_didIteratorError2) { + throw _iteratorError2; + } + } + } + + const retBuf = new ArrayBuffer(outputLength); + const retView = new Uint8Array(retBuf); + + var _iteratorNormalCompletion3 = true; + var _didIteratorError3 = false; + var _iteratorError3 = undefined; + + try { + for (var _iterator3 = buffers[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) { + const buffer = _step3.value; + + // noinspection NestedFunctionCallJS + retView.set(new Uint8Array(buffer), prevLength); + prevLength += buffer.byteLength; + } + } catch (err) { + _didIteratorError3 = true; + _iteratorError3 = err; + } finally { + try { + if (!_iteratorNormalCompletion3 && _iterator3.return) { + _iterator3.return(); + } + } finally { + if (_didIteratorError3) { + throw _iteratorError3; + } + } + } + + return retBuf; +} +//************************************************************************************** +// noinspection FunctionWithMultipleLoopsJS +/** + * Concatenate two Uint8Array + * @param {...Uint8Array} views Set of Uint8Array + */ +function utilConcatView(...views) { + //region Initial variables + let outputLength = 0; + let prevLength = 0; + //endregion + + //region Calculate output length + // noinspection NonBlockStatementBodyJS + var _iteratorNormalCompletion4 = true; + var _didIteratorError4 = false; + var _iteratorError4 = undefined; + + try { + for (var _iterator4 = views[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) { + const view = _step4.value; + + outputLength += view.length; + } //endregion + } catch (err) { + _didIteratorError4 = true; + _iteratorError4 = err; + } finally { + try { + if (!_iteratorNormalCompletion4 && _iterator4.return) { + _iterator4.return(); + } + } finally { + if (_didIteratorError4) { + throw _iteratorError4; + } + } + } + + const retBuf = new ArrayBuffer(outputLength); + const retView = new Uint8Array(retBuf); + + var _iteratorNormalCompletion5 = true; + var _didIteratorError5 = false; + var _iteratorError5 = undefined; + + try { + for (var _iterator5 = views[Symbol.iterator](), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) { + const view = _step5.value; + + retView.set(view, prevLength); + prevLength += view.length; + } + } catch (err) { + _didIteratorError5 = true; + _iteratorError5 = err; + } finally { + try { + if (!_iteratorNormalCompletion5 && _iterator5.return) { + _iterator5.return(); + } + } finally { + if (_didIteratorError5) { + throw _iteratorError5; + } + } + } + + return retView; +} +//************************************************************************************** +// noinspection FunctionWithMultipleLoopsJS +/** + * Decoding of "two complement" values + * The function must be called in scope of instance of "hexBlock" class ("valueHex" and "warnings" properties must be present) + * @returns {number} + */ +function utilDecodeTC() { + const buf = new Uint8Array(this.valueHex); + + // noinspection ConstantOnRightSideOfComparisonJS + if (this.valueHex.byteLength >= 2) { + //noinspection JSBitwiseOperatorUsage, ConstantOnRightSideOfComparisonJS, LocalVariableNamingConventionJS, MagicNumberJS, NonShortCircuitBooleanExpressionJS + const condition1 = buf[0] === 0xFF && buf[1] & 0x80; + // noinspection ConstantOnRightSideOfComparisonJS, LocalVariableNamingConventionJS, MagicNumberJS, NonShortCircuitBooleanExpressionJS + const condition2 = buf[0] === 0x00 && (buf[1] & 0x80) === 0x00; + + // noinspection NonBlockStatementBodyJS + if (condition1 || condition2) this.warnings.push("Needlessly long format"); + } + + //region Create big part of the integer + const bigIntBuffer = new ArrayBuffer(this.valueHex.byteLength); + const bigIntView = new Uint8Array(bigIntBuffer); + // noinspection NonBlockStatementBodyJS + for (let i = 0; i < this.valueHex.byteLength; i++) bigIntView[i] = 0; + + // noinspection MagicNumberJS, NonShortCircuitBooleanExpressionJS + bigIntView[0] = buf[0] & 0x80; // mask only the biggest bit + + const bigInt = utilFromBase(bigIntView, 8); + //endregion + + //region Create small part of the integer + const smallIntBuffer = new ArrayBuffer(this.valueHex.byteLength); + const smallIntView = new Uint8Array(smallIntBuffer); + // noinspection NonBlockStatementBodyJS + for (let j = 0; j < this.valueHex.byteLength; j++) smallIntView[j] = buf[j]; + + // noinspection MagicNumberJS + smallIntView[0] &= 0x7F; // mask biggest bit + + const smallInt = utilFromBase(smallIntView, 8); + //endregion + + return smallInt - bigInt; +} +//************************************************************************************** +// noinspection FunctionWithMultipleLoopsJS, FunctionWithMultipleReturnPointsJS +/** + * Encode integer value to "two complement" format + * @param {number} value Value to encode + * @returns {ArrayBuffer} + */ +function utilEncodeTC(value) { + // noinspection ConstantOnRightSideOfComparisonJS, ConditionalExpressionJS + const modValue = value < 0 ? value * -1 : value; + let bigInt = 128; + + // noinspection ConstantOnRightSideOfComparisonJS + for (let i = 1; i < 8; i++) { + if (modValue <= bigInt) { + // noinspection ConstantOnRightSideOfComparisonJS + if (value < 0) { + const smallInt = bigInt - modValue; + + const retBuf = utilToBase(smallInt, 8, i); + const retView = new Uint8Array(retBuf); + + // noinspection MagicNumberJS + retView[0] |= 0x80; + + return retBuf; + } + + let retBuf = utilToBase(modValue, 8, i); + let retView = new Uint8Array(retBuf); + + //noinspection JSBitwiseOperatorUsage, MagicNumberJS, NonShortCircuitBooleanExpressionJS + if (retView[0] & 0x80) { + //noinspection JSCheckFunctionSignatures + const tempBuf = retBuf.slice(0); + const tempView = new Uint8Array(tempBuf); + + retBuf = new ArrayBuffer(retBuf.byteLength + 1); + // noinspection ReuseOfLocalVariableJS + retView = new Uint8Array(retBuf); + + // noinspection NonBlockStatementBodyJS + for (let k = 0; k < tempBuf.byteLength; k++) retView[k + 1] = tempView[k]; + + // noinspection MagicNumberJS + retView[0] = 0x00; + } + + return retBuf; + } + + bigInt *= Math.pow(2, 8); + } + + return new ArrayBuffer(0); +} +//************************************************************************************** +// noinspection FunctionWithMultipleReturnPointsJS, ParameterNamingConventionJS +/** + * Compare two array buffers + * @param {!ArrayBuffer} inputBuffer1 + * @param {!ArrayBuffer} inputBuffer2 + * @returns {boolean} + */ +function isEqualBuffer(inputBuffer1, inputBuffer2) { + // noinspection NonBlockStatementBodyJS + if (inputBuffer1.byteLength !== inputBuffer2.byteLength) return false; + + // noinspection LocalVariableNamingConventionJS + const view1 = new Uint8Array(inputBuffer1); + // noinspection LocalVariableNamingConventionJS + const view2 = new Uint8Array(inputBuffer2); + + for (let i = 0; i < view1.length; i++) { + // noinspection NonBlockStatementBodyJS + if (view1[i] !== view2[i]) return false; + } + + return true; +} +//************************************************************************************** +// noinspection FunctionWithMultipleReturnPointsJS +/** + * Pad input number with leade "0" if needed + * @returns {string} + * @param {number} inputNumber + * @param {number} fullLength + */ +function padNumber(inputNumber, fullLength) { + const str = inputNumber.toString(10); + + // noinspection NonBlockStatementBodyJS + if (fullLength < str.length) return ""; + + const dif = fullLength - str.length; + + const padding = new Array(dif); + // noinspection NonBlockStatementBodyJS + for (let i = 0; i < dif; i++) padding[i] = "0"; + + const paddingString = padding.join(""); + + return paddingString.concat(str); +} +//************************************************************************************** +const base64Template = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; +const base64UrlTemplate = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_="; +//************************************************************************************** +// noinspection FunctionWithMultipleLoopsJS, OverlyComplexFunctionJS, FunctionTooLongJS, FunctionNamingConventionJS +/** + * Encode string into BASE64 (or "base64url") + * @param {string} input + * @param {boolean} useUrlTemplate If "true" then output would be encoded using "base64url" + * @param {boolean} skipPadding Skip BASE-64 padding or not + * @param {boolean} skipLeadingZeros Skip leading zeros in input data or not + * @returns {string} + */ +function toBase64(input, useUrlTemplate = false, skipPadding = false, skipLeadingZeros = false) { + let i = 0; + + // noinspection LocalVariableNamingConventionJS + let flag1 = 0; + // noinspection LocalVariableNamingConventionJS + let flag2 = 0; + + let output = ""; + + // noinspection ConditionalExpressionJS + const template = useUrlTemplate ? base64UrlTemplate : base64Template; + + if (skipLeadingZeros) { + let nonZeroPosition = 0; + + for (let i = 0; i < input.length; i++) { + // noinspection ConstantOnRightSideOfComparisonJS + if (input.charCodeAt(i) !== 0) { + nonZeroPosition = i; + // noinspection BreakStatementJS + break; + } + } + + // noinspection AssignmentToFunctionParameterJS + input = input.slice(nonZeroPosition); + } + + while (i < input.length) { + // noinspection LocalVariableNamingConventionJS, IncrementDecrementResultUsedJS + const chr1 = input.charCodeAt(i++); + // noinspection NonBlockStatementBodyJS + if (i >= input.length) flag1 = 1; + // noinspection LocalVariableNamingConventionJS, IncrementDecrementResultUsedJS + const chr2 = input.charCodeAt(i++); + // noinspection NonBlockStatementBodyJS + if (i >= input.length) flag2 = 1; + // noinspection LocalVariableNamingConventionJS, IncrementDecrementResultUsedJS + const chr3 = input.charCodeAt(i++); + + // noinspection LocalVariableNamingConventionJS + const enc1 = chr1 >> 2; + // noinspection LocalVariableNamingConventionJS, MagicNumberJS, NonShortCircuitBooleanExpressionJS + const enc2 = (chr1 & 0x03) << 4 | chr2 >> 4; + // noinspection LocalVariableNamingConventionJS, MagicNumberJS, NonShortCircuitBooleanExpressionJS + let enc3 = (chr2 & 0x0F) << 2 | chr3 >> 6; + // noinspection LocalVariableNamingConventionJS, MagicNumberJS, NonShortCircuitBooleanExpressionJS + let enc4 = chr3 & 0x3F; + + // noinspection ConstantOnRightSideOfComparisonJS + if (flag1 === 1) { + // noinspection NestedAssignmentJS, AssignmentResultUsedJS, MagicNumberJS + enc3 = enc4 = 64; + } else { + // noinspection ConstantOnRightSideOfComparisonJS + if (flag2 === 1) { + // noinspection MagicNumberJS + enc4 = 64; + } + } + + // noinspection NonBlockStatementBodyJS + if (skipPadding) { + // noinspection ConstantOnRightSideOfComparisonJS, NonBlockStatementBodyJS, MagicNumberJS + if (enc3 === 64) output += `${template.charAt(enc1)}${template.charAt(enc2)}`;else { + // noinspection ConstantOnRightSideOfComparisonJS, NonBlockStatementBodyJS, MagicNumberJS + if (enc4 === 64) output += `${template.charAt(enc1)}${template.charAt(enc2)}${template.charAt(enc3)}`;else output += `${template.charAt(enc1)}${template.charAt(enc2)}${template.charAt(enc3)}${template.charAt(enc4)}`; + } + } else output += `${template.charAt(enc1)}${template.charAt(enc2)}${template.charAt(enc3)}${template.charAt(enc4)}`; + } + + return output; +} +//************************************************************************************** +// noinspection FunctionWithMoreThanThreeNegationsJS, FunctionWithMultipleLoopsJS, OverlyComplexFunctionJS, FunctionNamingConventionJS +/** + * Decode string from BASE64 (or "base64url") + * @param {string} input + * @param {boolean} [useUrlTemplate=false] If "true" then output would be encoded using "base64url" + * @param {boolean} [cutTailZeros=false] If "true" then cut tailing zeroz from function result + * @returns {string} + */ +function fromBase64(input, useUrlTemplate = false, cutTailZeros = false) { + // noinspection ConditionalExpressionJS + const template = useUrlTemplate ? base64UrlTemplate : base64Template; + + //region Aux functions + // noinspection FunctionWithMultipleReturnPointsJS, NestedFunctionJS + function indexof(toSearch) { + // noinspection ConstantOnRightSideOfComparisonJS, MagicNumberJS + for (let i = 0; i < 64; i++) { + // noinspection NonBlockStatementBodyJS + if (template.charAt(i) === toSearch) return i; + } + + // noinspection MagicNumberJS + return 64; + } + + // noinspection NestedFunctionJS + function test(incoming) { + // noinspection ConstantOnRightSideOfComparisonJS, ConditionalExpressionJS, MagicNumberJS + return incoming === 64 ? 0x00 : incoming; + } + //endregion + + let i = 0; + + let output = ""; + + while (i < input.length) { + // noinspection NestedFunctionCallJS, LocalVariableNamingConventionJS, IncrementDecrementResultUsedJS + const enc1 = indexof(input.charAt(i++)); + // noinspection NestedFunctionCallJS, LocalVariableNamingConventionJS, ConditionalExpressionJS, MagicNumberJS, IncrementDecrementResultUsedJS + const enc2 = i >= input.length ? 0x00 : indexof(input.charAt(i++)); + // noinspection NestedFunctionCallJS, LocalVariableNamingConventionJS, ConditionalExpressionJS, MagicNumberJS, IncrementDecrementResultUsedJS + const enc3 = i >= input.length ? 0x00 : indexof(input.charAt(i++)); + // noinspection NestedFunctionCallJS, LocalVariableNamingConventionJS, ConditionalExpressionJS, MagicNumberJS, IncrementDecrementResultUsedJS + const enc4 = i >= input.length ? 0x00 : indexof(input.charAt(i++)); + + // noinspection LocalVariableNamingConventionJS, NonShortCircuitBooleanExpressionJS + const chr1 = test(enc1) << 2 | test(enc2) >> 4; + // noinspection LocalVariableNamingConventionJS, MagicNumberJS, NonShortCircuitBooleanExpressionJS + const chr2 = (test(enc2) & 0x0F) << 4 | test(enc3) >> 2; + // noinspection LocalVariableNamingConventionJS, MagicNumberJS, NonShortCircuitBooleanExpressionJS + const chr3 = (test(enc3) & 0x03) << 6 | test(enc4); + + output += String.fromCharCode(chr1); + + // noinspection ConstantOnRightSideOfComparisonJS, NonBlockStatementBodyJS, MagicNumberJS + if (enc3 !== 64) output += String.fromCharCode(chr2); + + // noinspection ConstantOnRightSideOfComparisonJS, NonBlockStatementBodyJS, MagicNumberJS + if (enc4 !== 64) output += String.fromCharCode(chr3); + } + + if (cutTailZeros) { + const outputLength = output.length; + let nonZeroStart = -1; + + // noinspection ConstantOnRightSideOfComparisonJS + for (let i = outputLength - 1; i >= 0; i--) { + // noinspection ConstantOnRightSideOfComparisonJS + if (output.charCodeAt(i) !== 0) { + nonZeroStart = i; + // noinspection BreakStatementJS + break; + } + } + + // noinspection NonBlockStatementBodyJS, NegatedIfStatementJS + if (nonZeroStart !== -1) output = output.slice(0, nonZeroStart + 1);else output = ""; + } + + return output; +} +//************************************************************************************** +function arrayBufferToString(buffer) { + let resultString = ""; + const view = new Uint8Array(buffer); + + // noinspection NonBlockStatementBodyJS + var _iteratorNormalCompletion6 = true; + var _didIteratorError6 = false; + var _iteratorError6 = undefined; + + try { + for (var _iterator6 = view[Symbol.iterator](), _step6; !(_iteratorNormalCompletion6 = (_step6 = _iterator6.next()).done); _iteratorNormalCompletion6 = true) { + const element = _step6.value; + + resultString += String.fromCharCode(element); + } + } catch (err) { + _didIteratorError6 = true; + _iteratorError6 = err; + } finally { + try { + if (!_iteratorNormalCompletion6 && _iterator6.return) { + _iterator6.return(); + } + } finally { + if (_didIteratorError6) { + throw _iteratorError6; + } + } + } + + return resultString; +} +//************************************************************************************** +function stringToArrayBuffer(str) { + const stringLength = str.length; + + const resultBuffer = new ArrayBuffer(stringLength); + const resultView = new Uint8Array(resultBuffer); + + // noinspection NonBlockStatementBodyJS + for (let i = 0; i < stringLength; i++) resultView[i] = str.charCodeAt(i); + + return resultBuffer; +} +//************************************************************************************** +const log2 = Math.log(2); +//************************************************************************************** +// noinspection FunctionNamingConventionJS +/** + * Get nearest to input length power of 2 + * @param {number} length Current length of existing array + * @returns {number} + */ +function nearestPowerOf2(length) { + const base = Math.log(length) / log2; + + const floor = Math.floor(base); + const round = Math.round(base); + + // noinspection ConditionalExpressionJS + return floor === round ? floor : round; +} +//************************************************************************************** +/** + * Delete properties by name from specified object + * @param {Object} object Object to delete properties from + * @param {Array.} propsArray Array of properties names + */ +function clearProps(object, propsArray) { + var _iteratorNormalCompletion7 = true; + var _didIteratorError7 = false; + var _iteratorError7 = undefined; + + try { + for (var _iterator7 = propsArray[Symbol.iterator](), _step7; !(_iteratorNormalCompletion7 = (_step7 = _iterator7.next()).done); _iteratorNormalCompletion7 = true) { + const prop = _step7.value; + + delete object[prop]; + } + } catch (err) { + _didIteratorError7 = true; + _iteratorError7 = err; + } finally { + try { + if (!_iteratorNormalCompletion7 && _iterator7.return) { + _iterator7.return(); + } + } finally { + if (_didIteratorError7) { + throw _iteratorError7; + } + } + } +} +//************************************************************************************** + +},{}],2:[function(require,module,exports){ +/* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +const pvutils = require("pvutils"); // version 1.0.17 + +module.exports = { + pvutils, +}; + +},{"pvutils":1}]},{},[2])(2) +}); diff --git a/toolkit/components/certviewer/jar.mn b/toolkit/components/certviewer/jar.mn index 736bc0e6804c..cdb631f32d78 100644 --- a/toolkit/components/certviewer/jar.mn +++ b/toolkit/components/certviewer/jar.mn @@ -13,3 +13,10 @@ toolkit.jar: content/global/certviewer/components/info-group.css (content/components/info-group.css) content/global/certviewer/components/info-item.js (content/components/info-item.js) content/global/certviewer/components/info-item.css (content/components/info-item.css) + content/global/certviewer/certDecoder.js (content/certDecoder.js) + content/global/certviewer/strings.js (content/strings.js) + content/global/certviewer/ctlognames.js (content/ctlognames.js) + content/global/certviewer/utils.js (content/utils.js) + content/global/certviewer/pvutils_bundle.js (content/vendor/pvutils_bundle.js) + content/global/certviewer/asn1js_bundle.js (content/vendor/asn1js_bundle.js) + content/global/certviewer/pkijs_bundle.js (content/vendor/pkijs_bundle.js) diff --git a/toolkit/content/directionDetector.html b/toolkit/content/directionDetector.html deleted file mode 100644 index 5e91ba7f5797..000000000000 --- a/toolkit/content/directionDetector.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - diff --git a/toolkit/content/jar.mn b/toolkit/content/jar.mn index d4e5313da869..2f64b0afa425 100644 --- a/toolkit/content/jar.mn +++ b/toolkit/content/jar.mn @@ -31,9 +31,9 @@ toolkit.jar: content/global/aboutUrlClassifier.js content/global/aboutUrlClassifier.xhtml content/global/aboutUrlClassifier.css - content/global/directionDetector.html content/global/plugins.html content/global/plugins.css + content/global/plugins.js content/global/browser-child.js content/global/browser-content.js * content/global/buildconfig.html diff --git a/toolkit/content/moz.build b/toolkit/content/moz.build index 529335c4f7a4..00118c5ac1d7 100644 --- a/toolkit/content/moz.build +++ b/toolkit/content/moz.build @@ -260,9 +260,6 @@ with Files('contentAreaUtils.js'): with Files('*picker*'): BUG_COMPONENT = ('Toolkit', 'XUL Widgets') -with Files('direction*'): - BUG_COMPONENT = ('Toolkit', 'XUL Widgets') - with Files('edit*'): BUG_COMPONENT = ('Toolkit', 'XUL Widgets') diff --git a/toolkit/content/plugins.html b/toolkit/content/plugins.html index 6bb2aa0ac5be..1e3dd0deaab4 100644 --- a/toolkit/content/plugins.html +++ b/toolkit/content/plugins.html @@ -6,216 +6,15 @@ + -
- +
diff --git a/toolkit/content/plugins.js b/toolkit/content/plugins.js new file mode 100644 index 000000000000..73c31f151b17 --- /dev/null +++ b/toolkit/content/plugins.js @@ -0,0 +1,199 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* eslint-env mozilla/frame-script */ + +"use strict"; + +const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm"); + +/* JavaScript to enumerate and display all installed plug-ins + + * First, refresh plugins in case anything has been changed recently in + * prefs: (The "false" argument tells refresh not to reload or activate + * any plug-ins that would be active otherwise. In contrast, one would + * use "true" in the case of ASD instead of restarting) + */ +navigator.plugins.refresh(false); + +RPMAddMessageListener("PluginList", function({ data: aPlugins }) { + var fragment = document.createDocumentFragment(); + + // "Installed plugins" + var id, label; + if (aPlugins.length > 0) { + id = "plugs"; + label = "installed-plugins-label"; + } else { + id = "noplugs"; + label = "no-plugins-are-installed-label"; + } + var enabledplugins = document.createElement("h1"); + enabledplugins.setAttribute("id", id); + document.l10n.setAttributes(enabledplugins, label); + fragment.appendChild(enabledplugins); + + var deprecation = document.createElement("p"); + var deprecationLink = document.createElement("a"); + let deprecationLink_href = + Services.urlFormatter.formatURLPref("app.support.baseURL") + "npapi"; + deprecationLink.setAttribute("data-l10n-name", "deprecation-link"); + deprecationLink.setAttribute("href", deprecationLink_href); + deprecation.appendChild(deprecationLink); + deprecation.setAttribute("class", "notice"); + document.l10n.setAttributes(deprecation, "deprecation-description"); + fragment.appendChild(deprecation); + + var stateNames = {}; + [ + "STATE_SOFTBLOCKED", + "STATE_BLOCKED", + "STATE_OUTDATED", + "STATE_VULNERABLE_UPDATE_AVAILABLE", + "STATE_VULNERABLE_NO_UPDATE", + ].forEach(function(label) { + stateNames[Ci.nsIBlocklistService[label]] = label; + }); + + for (var i = 0; i < aPlugins.length; i++) { + var plugin = aPlugins[i]; + if (plugin) { + // "Shockwave Flash" + var plugname = document.createElement("h2"); + plugname.setAttribute("class", "plugname"); + plugname.appendChild(document.createTextNode(plugin.name)); + fragment.appendChild(plugname); + + var dl = document.createElement("dl"); + fragment.appendChild(dl); + + // "File: Flash Player.plugin" + var fileDd = document.createElement("dd"); + var file = document.createElement("span"); + file.setAttribute("data-l10n-name", "file"); + file.setAttribute("class", "label"); + fileDd.appendChild(file); + document.l10n.setAttributes(fileDd, "file-dd", { + pluginLibraries: plugin.pluginLibraries[0], + }); + dl.appendChild(fileDd); + + // "Path: /usr/lib/mozilla/plugins/libtotem-cone-plugin.so" + var pathDd = document.createElement("dd"); + var path = document.createElement("span"); + path.setAttribute("data-l10n-name", "path"); + path.setAttribute("class", "label"); + pathDd.appendChild(path); + document.l10n.setAttributes(pathDd, "path-dd", { + pluginFullPath: plugin.pluginFullpath[0], + }); + dl.appendChild(pathDd); + + // "Version: " + var versionDd = document.createElement("dd"); + var version = document.createElement("span"); + version.setAttribute("data-l10n-name", "version"); + version.setAttribute("class", "label"); + versionDd.appendChild(version); + document.l10n.setAttributes(versionDd, "version-dd", { + version: plugin.version, + }); + dl.appendChild(versionDd); + + // "State: " + var stateDd = document.createElement("dd"); + var state = document.createElement("span"); + state.setAttribute("data-l10n-name", "state"); + state.setAttribute("label", "state"); + stateDd.appendChild(state); + if (plugin.isActive) { + if (plugin.blocklistState in stateNames) { + document.l10n.setAttributes( + stateDd, + "state-dd-enabled-block-list-state", + { blockListState: stateNames[plugin.blocklistState] } + ); + } else { + document.l10n.setAttributes(stateDd, "state-dd-enabled"); + } + } else if (plugin.blocklistState in stateNames) { + document.l10n.setAttributes( + stateDd, + "state-dd-disabled-block-list-state", + { blockListState: stateNames[plugin.blocklistState] } + ); + } else { + document.l10n.setAttributes(stateDd, "state-dd-disabled"); + } + dl.appendChild(stateDd); + + // Plugin Description + var descDd = document.createElement("dd"); + descDd.appendChild(document.createTextNode(plugin.description)); + dl.appendChild(descDd); + + // MIME Type table + var mimetypeTable = document.createElement("table"); + mimetypeTable.setAttribute("border", "1"); + mimetypeTable.setAttribute("class", "contenttable"); + fragment.appendChild(mimetypeTable); + + var thead = document.createElement("thead"); + mimetypeTable.appendChild(thead); + var tr = document.createElement("tr"); + thead.appendChild(tr); + + // "MIME Type" column header + var typeTh = document.createElement("th"); + typeTh.setAttribute("class", "type"); + document.l10n.setAttributes(typeTh, "mime-type-label"); + tr.appendChild(typeTh); + + // "Description" column header + var descTh = document.createElement("th"); + descTh.setAttribute("class", "desc"); + document.l10n.setAttributes(descTh, "description-label"); + tr.appendChild(descTh); + + // "Suffixes" column header + var suffixesTh = document.createElement("th"); + suffixesTh.setAttribute("class", "suff"); + document.l10n.setAttributes(suffixesTh, "suffixes-label"); + tr.appendChild(suffixesTh); + + var tbody = document.createElement("tbody"); + mimetypeTable.appendChild(tbody); + + var mimeTypes = plugin.pluginMimeTypes; + for (var j = 0; j < mimeTypes.length; j++) { + var mimetype = mimeTypes[j]; + if (mimetype) { + var mimetypeRow = document.createElement("tr"); + tbody.appendChild(mimetypeRow); + + // "application/x-shockwave-flash" + var typename = document.createElement("td"); + typename.appendChild(document.createTextNode(mimetype.type)); + mimetypeRow.appendChild(typename); + + // "Shockwave Flash" + var description = document.createElement("td"); + description.appendChild( + document.createTextNode(mimetype.description) + ); + mimetypeRow.appendChild(description); + + // "swf" + var suffixes = document.createElement("td"); + suffixes.appendChild(document.createTextNode(mimetype.suffixes)); + mimetypeRow.appendChild(suffixes); + } + } + } + } + + document.getElementById("outside").appendChild(fragment); +}); + +RPMSendAsyncMessage("RequestPlugins"); diff --git a/toolkit/locales/en-US/toolkit/about/aboutAddons.ftl b/toolkit/locales/en-US/toolkit/about/aboutAddons.ftl index ffdd8aa4f2f8..f2e2942f15d0 100644 --- a/toolkit/locales/en-US/toolkit/about/aboutAddons.ftl +++ b/toolkit/locales/en-US/toolkit/about/aboutAddons.ftl @@ -383,7 +383,6 @@ report-addon-button = Report remove-addon-button = Remove disable-addon-button = Disable enable-addon-button = Enable -expand-addon-button = More Options preferences-addon-button = { PLATFORM() -> [windows] Options diff --git a/toolkit/mozapps/extensions/content/aboutaddons.html b/toolkit/mozapps/extensions/content/aboutaddons.html index 2553a8044a2f..af15faa64a4a 100644 --- a/toolkit/mozapps/extensions/content/aboutaddons.html +++ b/toolkit/mozapps/extensions/content/aboutaddons.html @@ -40,7 +40,7 @@ - + @@ -52,7 +52,7 @@ - + diff --git a/tools/rewriting/ThirdPartyPaths.txt b/tools/rewriting/ThirdPartyPaths.txt index e5712d7489fd..3c51f13f0b14 100644 --- a/tools/rewriting/ThirdPartyPaths.txt +++ b/tools/rewriting/ThirdPartyPaths.txt @@ -122,6 +122,7 @@ testing/web-platform/tests/tools/third_party/ testing/xpcshell/node-ip/ testing/xpcshell/dns-packet/ third_party/ +toolkit/components/certviewer/content/vendor/ toolkit/components/jsoncpp/ toolkit/components/normandy/vendor/ toolkit/components/protobuf/ diff --git a/tools/tryselect/try_presets.yml b/tools/tryselect/try_presets.yml index c7565ad10457..73c33bf5a2c6 100644 --- a/tools/tryselect/try_presets.yml +++ b/tools/tryselect/try_presets.yml @@ -85,3 +85,11 @@ sm-all: - "!android !asan !shippable 'xpcshell" - "!android !asan !shippable 'jsreftest" - "!shippable !android 'jittest" # macosx64 jittests + +webrender: + selector: fuzzy + description: >- + Runs the conformance tests relevant to WebRender. + query: + - "!talos !raptor !shippable !asan '-qr" + - "^webrender-" diff --git a/uriloader/exthandler/nsExternalProtocolHandler.cpp b/uriloader/exthandler/nsExternalProtocolHandler.cpp index 64b282919623..8af65dd34691 100644 --- a/uriloader/exthandler/nsExternalProtocolHandler.cpp +++ b/uriloader/exthandler/nsExternalProtocolHandler.cpp @@ -372,7 +372,7 @@ NS_IMETHODIMP nsExtProtocolChannel::CompleteRedirectSetup( ////////////////////////////////////////////////////////////////////// NS_IMETHODIMP nsExtProtocolChannel::SetParentListener( - mozilla::net::HttpChannelParentListener* aListener) { + mozilla::net::ParentChannelListener* aListener) { // This is called as part of the connect parent operation from // ContentParent::RecvExtProtocolChannelConnectParent. Setting // this flag tells this channel to not proceed and makes AsyncOpen