From 3deafe34efca00b5b7100a93fcf0cd6bd99bb7b6 Mon Sep 17 00:00:00 2001
From: Ylian Saint-Hilaire
Date: Mon, 9 Mar 2020 11:11:06 -0700
Subject: [PATCH] first commit
---
.gitignore | 293 +
LICENSE | 201 +
VSSolution.sln | 38 +
agent-desktop-0.0.2.js | 781 +
agent-redir-rtc-0.1.0.js | 145 +
amt-0.2.0.js | 987 +
amt-certificates-0.0.1.js | 181 +
amt-desktop-0.0.2.js | 923 +
amt-ider-node-0.0.1.js | 509 +
amt-ider-server-ws-0.0.1.js | 100 +
amt-ider-ws-0.0.1.js | 692 +
amt-lms-0.0.1.js | 104 +
amt-redir-node-0.1.0.js | 323 +
amt-redir-ws-0.1.0.js | 335 +
amt-scanner-0.1.0.js | 235 +
amt-script-0.2.0.js | 440 +
amt-setupbin-0.1.0.js | 273 +
amt-terminal-0.0.2.js | 813 +
amt-wsman-0.2.0.js | 336 +
amt-wsman-ajax-0.2.0.js | 95 +
amt-wsman-node-0.2.0.js | 392 +
amt-wsman-ws-0.2.0.js | 315 +
certificate.png | Bin 0 -> 529 bytes
closure-externs/crypto.js | 578 +
closure-externs/net.js | 249 +
closure-externs/tls.js | 144 +
common-0.0.1.js | 105 +
desktop.ini | 2 +
favicon-intel.ico | Bin 0 -> 144613 bytes
favicon-intel.png | Bin 0 -> 3263 bytes
favicon.ico | Bin 0 -> 119195 bytes
favicon.png | Bin 0 -> 3200 bytes
filesaver.1.1.20151003.js | 270 +
forge.js/aes.js | 1147 +
forge.js/aesCipherSuites.js | 338 +
forge.js/asn1.js | 1157 +
forge.js/cipher.js | 286 +
forge.js/cipherModes.js | 1049 +
forge.js/debug.js | 134 +
forge.js/des.js | 552 +
forge.js/forge.bundle.js | 29553 +++++++++++
forge.js/forge.js | 92 +
forge.js/form.js | 157 +
forge.js/hmac.js | 200 +
forge.js/http.js | 1369 +
forge.js/jsbn.js | 1321 +
forge.js/kem.js | 221 +
forge.js/log.js | 372 +
forge.js/md.js | 75 +
forge.js/md5.js | 345 +
forge.js/mgf.js | 67 +
forge.js/mgf1.js | 112 +
forge.js/oids.js | 269 +
forge.js/pbe.js | 975 +
forge.js/pbkdf2.js | 264 +
forge.js/pem.js | 285 +
forge.js/pkcs1.js | 329 +
forge.js/pkcs12.js | 1133 +
forge.js/pkcs7.js | 1301 +
forge.js/pkcs7asn1.js | 463 +
forge.js/pki.js | 161 +
forge.js/prime.js | 337 +
forge.js/prime.worker.js | 165 +
forge.js/prng.js | 458 +
forge.js/pss.js | 295 +
forge.js/random.js | 237 +
forge.js/rc2.js | 470 +
forge.js/rsa.js | 1714 +
forge.js/sha1.js | 369 +
forge.js/sha256.js | 379 +
forge.js/sha512.js | 603 +
forge.js/socket.js | 342 +
forge.js/ssh.js | 295 +
forge.js/task.js | 778 +
forge.js/tls.js | 4316 ++
forge.js/tlssocket.js | 304 +
forge.js/util.js | 2988 ++
forge.js/x509.js | 3191 ++
forge.js/xhr.js | 739 +
images-commander/Thumbs.db | Bin 0 -> 15872 bytes
images-commander/certificate-1.png | Bin 0 -> 1805 bytes
images-commander/error.gif | Bin 0 -> 149 bytes
images-commander/error.png | Bin 0 -> 3627 bytes
images-commander/icons16.png | Bin 0 -> 2201 bytes
images-commander/icons200-1-1.png | Bin 0 -> 31115 bytes
images-commander/icons200-2-1.png | Bin 0 -> 38317 bytes
images-commander/icons200-3-1.png | Bin 0 -> 36056 bytes
images-commander/icons200-4-1.png | Bin 0 -> 16920 bytes
images-commander/icons200-5-1.png | Bin 0 -> 22616 bytes
images-commander/icons200-6-1.png | Bin 0 -> 23365 bytes
images-commander/icons26.png | Bin 0 -> 9118 bytes
images-commander/icons50.png | Bin 0 -> 17385 bytes
images-commander/info.gif | Bin 0 -> 197 bytes
images-commander/info.png | Bin 0 -> 3565 bytes
images-commander/leftbar-32.png | Bin 0 -> 4932 bytes
images-commander/leftbar-44.png | Bin 0 -> 7860 bytes
images-commander/logo-old.png | Bin 0 -> 14784 bytes
images-commander/logo.png | Bin 0 -> 12031 bytes
images-commander/logoback.png | Bin 0 -> 21683 bytes
images-commander/logox.png | Bin 0 -> 13224 bytes
images-commander/warn.gif | Bin 0 -> 97 bytes
images-commander/warn.png | Bin 0 -> 3347 bytes
images-commander/warning.png | Bin 0 -> 3177 bytes
images/lock.gif | Bin 0 -> 106 bytes
index.html | 12896 +++++
mesh256.png | Bin 0 -> 19615 bytes
mesh256s.png | Bin 0 -> 18647 bytes
mesh32s.png | Bin 0 -> 1538 bytes
meshcentral-server-0.2.0.js | 286 +
output/Firmware-Large.gz | Bin 0 -> 72465 bytes
output/Firmware-Medium.gz | Bin 0 -> 61277 bytes
output/Firmware-Small.gz | Bin 0 -> 40420 bytes
output/index.htm | 50840 +++++++++++++++++++
package.json | 18 +
readme.md | 59 +
scriptblocks.txt | 947 +
styles-branded.css | 292 +
styles-brandedcommander.css | 297 +
styles-commander.css | 523 +
styles-isdu.css | 295 +
styles-mesh.css | 286 +
web.config | 6 +
webrelay.ashx | 175 +
websitecompiler/Firmware-MeshCommander.wcc | Bin 0 -> 4890 bytes
websitecompiler/NodeWebkit-Commander.wcc | Bin 0 -> 4893 bytes
websocket-wrapper-0.2.0.js | 206 +
zlib-adler32.js | 279 +
zlib-crc32.js | 246 +
zlib-inflate.js | 1955 +
zlib.js | 111 +
130 files changed, 141283 insertions(+)
create mode 100644 .gitignore
create mode 100644 LICENSE
create mode 100644 VSSolution.sln
create mode 100644 agent-desktop-0.0.2.js
create mode 100644 agent-redir-rtc-0.1.0.js
create mode 100644 amt-0.2.0.js
create mode 100644 amt-certificates-0.0.1.js
create mode 100644 amt-desktop-0.0.2.js
create mode 100644 amt-ider-node-0.0.1.js
create mode 100644 amt-ider-server-ws-0.0.1.js
create mode 100644 amt-ider-ws-0.0.1.js
create mode 100644 amt-lms-0.0.1.js
create mode 100644 amt-redir-node-0.1.0.js
create mode 100644 amt-redir-ws-0.1.0.js
create mode 100644 amt-scanner-0.1.0.js
create mode 100644 amt-script-0.2.0.js
create mode 100644 amt-setupbin-0.1.0.js
create mode 100644 amt-terminal-0.0.2.js
create mode 100644 amt-wsman-0.2.0.js
create mode 100644 amt-wsman-ajax-0.2.0.js
create mode 100644 amt-wsman-node-0.2.0.js
create mode 100644 amt-wsman-ws-0.2.0.js
create mode 100644 certificate.png
create mode 100644 closure-externs/crypto.js
create mode 100644 closure-externs/net.js
create mode 100644 closure-externs/tls.js
create mode 100644 common-0.0.1.js
create mode 100644 desktop.ini
create mode 100644 favicon-intel.ico
create mode 100644 favicon-intel.png
create mode 100644 favicon.ico
create mode 100644 favicon.png
create mode 100644 filesaver.1.1.20151003.js
create mode 100644 forge.js/aes.js
create mode 100644 forge.js/aesCipherSuites.js
create mode 100644 forge.js/asn1.js
create mode 100644 forge.js/cipher.js
create mode 100644 forge.js/cipherModes.js
create mode 100644 forge.js/debug.js
create mode 100644 forge.js/des.js
create mode 100644 forge.js/forge.bundle.js
create mode 100644 forge.js/forge.js
create mode 100644 forge.js/form.js
create mode 100644 forge.js/hmac.js
create mode 100644 forge.js/http.js
create mode 100644 forge.js/jsbn.js
create mode 100644 forge.js/kem.js
create mode 100644 forge.js/log.js
create mode 100644 forge.js/md.js
create mode 100644 forge.js/md5.js
create mode 100644 forge.js/mgf.js
create mode 100644 forge.js/mgf1.js
create mode 100644 forge.js/oids.js
create mode 100644 forge.js/pbe.js
create mode 100644 forge.js/pbkdf2.js
create mode 100644 forge.js/pem.js
create mode 100644 forge.js/pkcs1.js
create mode 100644 forge.js/pkcs12.js
create mode 100644 forge.js/pkcs7.js
create mode 100644 forge.js/pkcs7asn1.js
create mode 100644 forge.js/pki.js
create mode 100644 forge.js/prime.js
create mode 100644 forge.js/prime.worker.js
create mode 100644 forge.js/prng.js
create mode 100644 forge.js/pss.js
create mode 100644 forge.js/random.js
create mode 100644 forge.js/rc2.js
create mode 100644 forge.js/rsa.js
create mode 100644 forge.js/sha1.js
create mode 100644 forge.js/sha256.js
create mode 100644 forge.js/sha512.js
create mode 100644 forge.js/socket.js
create mode 100644 forge.js/ssh.js
create mode 100644 forge.js/task.js
create mode 100644 forge.js/tls.js
create mode 100644 forge.js/tlssocket.js
create mode 100644 forge.js/util.js
create mode 100644 forge.js/x509.js
create mode 100644 forge.js/xhr.js
create mode 100644 images-commander/Thumbs.db
create mode 100644 images-commander/certificate-1.png
create mode 100644 images-commander/error.gif
create mode 100644 images-commander/error.png
create mode 100644 images-commander/icons16.png
create mode 100644 images-commander/icons200-1-1.png
create mode 100644 images-commander/icons200-2-1.png
create mode 100644 images-commander/icons200-3-1.png
create mode 100644 images-commander/icons200-4-1.png
create mode 100644 images-commander/icons200-5-1.png
create mode 100644 images-commander/icons200-6-1.png
create mode 100644 images-commander/icons26.png
create mode 100644 images-commander/icons50.png
create mode 100644 images-commander/info.gif
create mode 100644 images-commander/info.png
create mode 100644 images-commander/leftbar-32.png
create mode 100644 images-commander/leftbar-44.png
create mode 100644 images-commander/logo-old.png
create mode 100644 images-commander/logo.png
create mode 100644 images-commander/logoback.png
create mode 100644 images-commander/logox.png
create mode 100644 images-commander/warn.gif
create mode 100644 images-commander/warn.png
create mode 100644 images-commander/warning.png
create mode 100644 images/lock.gif
create mode 100644 index.html
create mode 100644 mesh256.png
create mode 100644 mesh256s.png
create mode 100644 mesh32s.png
create mode 100644 meshcentral-server-0.2.0.js
create mode 100644 output/Firmware-Large.gz
create mode 100644 output/Firmware-Medium.gz
create mode 100644 output/Firmware-Small.gz
create mode 100644 output/index.htm
create mode 100644 package.json
create mode 100644 readme.md
create mode 100644 scriptblocks.txt
create mode 100644 styles-branded.css
create mode 100644 styles-brandedcommander.css
create mode 100644 styles-commander.css
create mode 100644 styles-isdu.css
create mode 100644 styles-mesh.css
create mode 100644 web.config
create mode 100644 webrelay.ashx
create mode 100644 websitecompiler/Firmware-MeshCommander.wcc
create mode 100644 websitecompiler/NodeWebkit-Commander.wcc
create mode 100644 websocket-wrapper-0.2.0.js
create mode 100644 zlib-adler32.js
create mode 100644 zlib-crc32.js
create mode 100644 zlib-inflate.js
create mode 100644 zlib.js
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..197fccb
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,293 @@
+## Ignore nodejs things
+[Ii]mages-branded/
+[Ii]mages-brandedcommander/
+[Ii]mages-isdu
+
+## Ignore Visual Studio temporary files, build results, and
+## files generated by popular Visual Studio add-ons.
+##
+## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
+
+# User-specific files
+*.suo
+*.user
+*.userosscache
+*.sln.docstates
+
+# User-specific files (MonoDevelop/Xamarin Studio)
+*.userprefs
+
+# Build results
+[Dd]ebug/
+[Dd]ebugPublic/
+[Rr]elease/
+[Rr]eleases/
+x64/
+x86/
+bld/
+[Bb]in/
+[Oo]bj/
+[Ll]og/
+
+# Visual Studio 2015 cache/options directory
+.vs/
+# Uncomment if you have tasks that create the project's static files in wwwroot
+#wwwroot/
+
+# MSTest test Results
+[Tt]est[Rr]esult*/
+[Bb]uild[Ll]og.*
+
+# NUNIT
+*.VisualState.xml
+TestResult.xml
+
+# Build Results of an ATL Project
+[Dd]ebugPS/
+[Rr]eleasePS/
+dlldata.c
+
+# .NET Core
+project.lock.json
+project.fragment.lock.json
+artifacts/
+**/Properties/launchSettings.json
+
+*_i.c
+*_p.c
+*_i.h
+*.ilk
+*.meta
+*.obj
+*.pch
+*.pdb
+*.pgc
+*.pgd
+*.rsp
+*.sbr
+*.tlb
+*.tli
+*.tlh
+*.tmp
+*.tmp_proj
+*.log
+*.vspscc
+*.vssscc
+.builds
+*.pidb
+*.svclog
+*.scc
+
+# Chutzpah Test files
+_Chutzpah*
+
+# Visual C++ cache files
+ipch/
+*.aps
+*.ncb
+*.opendb
+*.opensdf
+*.sdf
+*.cachefile
+*.VC.db
+*.VC.VC.opendb
+
+# Visual Studio profiler
+*.psess
+*.vsp
+*.vspx
+*.sap
+
+# TFS 2012 Local Workspace
+$tf/
+
+# Guidance Automation Toolkit
+*.gpState
+
+# ReSharper is a .NET coding add-in
+_ReSharper*/
+*.[Rr]e[Ss]harper
+*.DotSettings.user
+
+# JustCode is a .NET coding add-in
+.JustCode
+
+# TeamCity is a build add-in
+_TeamCity*
+
+# DotCover is a Code Coverage Tool
+*.dotCover
+
+# Visual Studio code coverage results
+*.coverage
+*.coveragexml
+
+# NCrunch
+_NCrunch_*
+.*crunch*.local.xml
+nCrunchTemp_*
+
+# MightyMoose
+*.mm.*
+AutoTest.Net/
+
+# Web workbench (sass)
+.sass-cache/
+
+# Installshield output folder
+[Ee]xpress/
+
+# DocProject is a documentation generator add-in
+DocProject/buildhelp/
+DocProject/Help/*.HxT
+DocProject/Help/*.HxC
+DocProject/Help/*.hhc
+DocProject/Help/*.hhk
+DocProject/Help/*.hhp
+DocProject/Help/Html2
+DocProject/Help/html
+
+# Click-Once directory
+publish/
+
+# Publish Web Output
+*.[Pp]ublish.xml
+*.azurePubxml
+# TODO: Comment the next line if you want to checkin your web deploy settings
+# but database connection strings (with potential passwords) will be unencrypted
+*.pubxml
+*.publishproj
+
+# Microsoft Azure Web App publish settings. Comment the next line if you want to
+# checkin your Azure Web App publish settings, but sensitive information contained
+# in these scripts will be unencrypted
+PublishScripts/
+
+# NuGet Packages
+*.nupkg
+# The packages folder can be ignored because of Package Restore
+**/packages/*
+# except build/, which is used as an MSBuild target.
+!**/packages/build/
+# Uncomment if necessary however generally it will be regenerated when needed
+#!**/packages/repositories.config
+# NuGet v3's project.json files produces more ignorable files
+*.nuget.props
+*.nuget.targets
+
+# Microsoft Azure Build Output
+csx/
+*.build.csdef
+
+# Microsoft Azure Emulator
+ecf/
+rcf/
+
+# Windows Store app package directories and files
+AppPackages/
+BundleArtifacts/
+Package.StoreAssociation.xml
+_pkginfo.txt
+
+# Visual Studio cache files
+# files ending in .cache can be ignored
+*.[Cc]ache
+# but keep track of directories ending in .cache
+!*.[Cc]ache/
+
+# Others
+ClientBin/
+~$*
+*~
+*.dbmdl
+*.dbproj.schemaview
+*.jfm
+*.pfx
+*.publishsettings
+orleans.codegen.cs
+
+# Since there are multiple workflows, uncomment next line to ignore bower_components
+# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
+#bower_components/
+
+# RIA/Silverlight projects
+Generated_Code/
+
+# Backup & report files from converting an old project file
+# to a newer Visual Studio version. Backup files are not needed,
+# because we have git ;-)
+_UpgradeReport_Files/
+Backup*/
+UpgradeLog*.XML
+UpgradeLog*.htm
+
+# SQL Server files
+*.mdf
+*.ldf
+*.ndf
+
+# Business Intelligence projects
+*.rdl.data
+*.bim.layout
+*.bim_*.settings
+
+# Microsoft Fakes
+FakesAssemblies/
+
+# GhostDoc plugin setting file
+*.GhostDoc.xml
+
+# Node.js Tools for Visual Studio
+.ntvs_analysis.dat
+node_modules/
+
+# Typescript v1 declaration files
+typings/
+
+# Visual Studio 6 build log
+*.plg
+
+# Visual Studio 6 workspace options file
+*.opt
+
+# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
+*.vbw
+
+# Visual Studio LightSwitch build output
+**/*.HTMLClient/GeneratedArtifacts
+**/*.DesktopClient/GeneratedArtifacts
+**/*.DesktopClient/ModelManifest.xml
+**/*.Server/GeneratedArtifacts
+**/*.Server/ModelManifest.xml
+_Pvt_Extensions
+
+# Paket dependency manager
+.paket/paket.exe
+paket-files/
+
+# FAKE - F# Make
+.fake/
+
+# JetBrains Rider
+.idea/
+*.sln.iml
+
+# CodeRush
+.cr/
+
+# Python Tools for Visual Studio (PTVS)
+__pycache__/
+*.pyc
+
+# Cake - Uncomment if you are using it
+# tools/**
+# !tools/packages.config
+
+# Telerik's JustMock configuration file
+*.jmconfig
+
+# BizTalk build output
+*.btp.cs
+*.btm.cs
+*.odx.cs
+*.xsd.cs
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..4667732
--- /dev/null
+++ b/LICENSE
@@ -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 2017-2020 Intel Corporation
+
+ 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/VSSolution.sln b/VSSolution.sln
new file mode 100644
index 0000000..84015b8
--- /dev/null
+++ b/VSSolution.sln
@@ -0,0 +1,38 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 14
+VisualStudioVersion = 14.0.23107.0
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{E24C65DC-7377-472B-9ABA-BC803B73C61A}") = "Source", ".", "{431BAB2D-8D6E-43E6-B9E9-A7A286AA1CF8}"
+ ProjectSection(WebsiteProperties) = preProject
+ TargetFrameworkMoniker = ".NETFramework,Version%3Dv4.0"
+ Debug.AspNetCompiler.VirtualPath = "/localhost_56807"
+ Debug.AspNetCompiler.PhysicalPath = "..\Source\"
+ Debug.AspNetCompiler.TargetPath = "PrecompiledWeb\localhost_56807\"
+ Debug.AspNetCompiler.Updateable = "true"
+ Debug.AspNetCompiler.ForceOverwrite = "true"
+ Debug.AspNetCompiler.FixedNames = "false"
+ Debug.AspNetCompiler.Debug = "True"
+ Release.AspNetCompiler.VirtualPath = "/localhost_56807"
+ Release.AspNetCompiler.PhysicalPath = "..\Source\"
+ Release.AspNetCompiler.TargetPath = "PrecompiledWeb\localhost_56807\"
+ Release.AspNetCompiler.Updateable = "true"
+ Release.AspNetCompiler.ForceOverwrite = "true"
+ Release.AspNetCompiler.FixedNames = "false"
+ Release.AspNetCompiler.Debug = "False"
+ VWDPort = "56807"
+ SlnRelativePath = "..\Source\"
+ EndProjectSection
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {431BAB2D-8D6E-43E6-B9E9-A7A286AA1CF8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {431BAB2D-8D6E-43E6-B9E9-A7A286AA1CF8}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/agent-desktop-0.0.2.js b/agent-desktop-0.0.2.js
new file mode 100644
index 0000000..2e9f148
--- /dev/null
+++ b/agent-desktop-0.0.2.js
@@ -0,0 +1,781 @@
+/**
+* @description Remote Desktop
+* @author Ylian Saint-Hilaire
+* @version v0.0.2g
+*/
+
+// Construct a MeshServer object
+var CreateAgentRemoteDesktop = function (canvasid, scrolldiv) {
+ var obj = {}
+ obj.CanvasId = canvasid;
+ if (typeof canvasid === 'string') obj.CanvasId = Q(canvasid);
+ obj.Canvas = obj.CanvasId.getContext("2d");
+ obj.scrolldiv = scrolldiv;
+ obj.State = 0;
+ obj.PendingOperations = [];
+ obj.tilesReceived = 0;
+ obj.TilesDrawn = 0;
+ obj.KillDraw = 0;
+ obj.ipad = false;
+ obj.tabletKeyboardVisible = false;
+ obj.LastX = 0;
+ obj.LastY = 0;
+ obj.touchenabled = 0;
+ obj.submenuoffset = 0;
+ obj.touchtimer = null;
+ obj.TouchArray = {};
+ obj.connectmode = 0; // 0 = HTTP, 1 = WebSocket, 2 = WebRTC
+ obj.connectioncount = 0;
+ obj.rotation = 0;
+ obj.protocol = 2; // KVM
+ obj.debugmode = 0;
+ obj.firstUpKeys = [];
+ obj.stopInput = false;
+ obj.localKeyMap = true;
+ obj.altPressed = false;
+ obj.ctrlPressed = false;
+ obj.shiftPressed = false;
+
+ obj.sessionid = 0;
+ obj.username;
+ obj.oldie = false;
+ obj.CompressionLevel = 50;
+ obj.ScalingLevel = 1024;
+ obj.FrameRateTimer = 50;
+ obj.FirstDraw = false;
+
+ obj.ScreenWidth = 960;
+ obj.ScreenHeight = 700;
+ obj.width = 960;
+ obj.height = 960;
+
+ obj.onScreenSizeChange = null;
+ obj.onMessage = null;
+ obj.onConnectCountChanged = null;
+ obj.onDebugMessage = null;
+ obj.onTouchEnabledChanged = null;
+ obj.onDisplayinfo = null;
+ obj.accumulator = null;
+
+ obj.Start = function () {
+ obj.State = 0;
+ obj.accumulator = null;
+ }
+
+ obj.Stop = function () {
+ obj.setRotation(0);
+ obj.UnGrabKeyInput();
+ obj.UnGrabMouseInput();
+ obj.touchenabled = 0;
+ if (obj.onScreenSizeChange != null) obj.onScreenSizeChange(obj, obj.ScreenWidth, obj.ScreenHeight, obj.CanvasId);
+ obj.Canvas.clearRect(0, 0, obj.CanvasId.width, obj.CanvasId.height);
+ }
+
+ obj.xxStateChange = function (newstate) {
+ if (obj.State == newstate) return;
+ obj.State = newstate;
+ obj.CanvasId.style.cursor = 'default';
+ //console.log('xxStateChange', newstate);
+ switch (newstate) {
+ case 0: {
+ // Disconnect
+ obj.Stop();
+ break;
+ }
+ case 3: {
+ // Websocket connected
+
+ break;
+ }
+ }
+ }
+
+ obj.send = function (x) {
+ if (obj.debugmode > 1) { console.log("KSend(" + x.length + "): " + rstr2hex(x)); }
+ if (obj.parent != null) { obj.parent.send(x); }
+ }
+
+ // KVM Control.
+ // Routines for processing incoming packets from the AJAX server, and handling individual messages.
+ obj.ProcessPictureMsg = function (str, X, Y) {
+ //if (obj.targetnode != null) obj.Debug("ProcessPictureMsg " + X + "," + Y + " - " + obj.targetnode.substring(0, 8));
+ var tile = new Image();
+ tile.xcount = obj.tilesReceived++;
+ //console.log('Tile #' + tile.xcount);
+ var r = obj.tilesReceived;
+ tile.src = "data:image/jpeg;base64," + btoa(str.substring(4, str.length));
+ tile.onload = function () {
+ //console.log('DecodeTile #' + this.xcount);
+ if (obj.Canvas != null && obj.KillDraw < r && obj.State != 0) {
+ obj.PendingOperations.push([r, 2, tile, X, Y]);
+ while (obj.DoPendingOperations()) { }
+ }
+ }
+ tile.error = function () { console.log('DecodeTileError'); }
+ }
+
+ obj.DoPendingOperations = function () {
+ if (obj.PendingOperations.length == 0) return false;
+ for (var i = 0; i < obj.PendingOperations.length; i++) { // && KillDraw < tilesDrawn
+ var Msg = obj.PendingOperations[i];
+ if (Msg[0] == (obj.TilesDrawn + 1)) {
+ if (Msg[1] == 1) { obj.ProcessCopyRectMsg(Msg[2]); }
+ else if (Msg[1] == 2) { obj.Canvas.drawImage(Msg[2], obj.rotX(Msg[3], Msg[4]), obj.rotY(Msg[3], Msg[4])); delete Msg[2]; }
+ obj.PendingOperations.splice(i, 1);
+ delete Msg;
+ obj.TilesDrawn++;
+ if (obj.TilesDrawn == obj.tilesReceived && obj.KillDraw < obj.TilesDrawn) { obj.KillDraw = obj.TilesDrawn = obj.tilesReceived = 0; }
+ return true;
+ }
+ }
+ if (obj.oldie && obj.PendingOperations.length > 0) { obj.TilesDrawn++; }
+ return false;
+ }
+
+ obj.ProcessCopyRectMsg = function (str) {
+ var SX = ((str.charCodeAt(0) & 0xFF) << 8) + (str.charCodeAt(1) & 0xFF);
+ var SY = ((str.charCodeAt(2) & 0xFF) << 8) + (str.charCodeAt(3) & 0xFF);
+ var DX = ((str.charCodeAt(4) & 0xFF) << 8) + (str.charCodeAt(5) & 0xFF);
+ var DY = ((str.charCodeAt(6) & 0xFF) << 8) + (str.charCodeAt(7) & 0xFF);
+ var WIDTH = ((str.charCodeAt(8) & 0xFF) << 8) + (str.charCodeAt(9) & 0xFF);
+ var HEIGHT = ((str.charCodeAt(10) & 0xFF) << 8) + (str.charCodeAt(11) & 0xFF);
+ obj.Canvas.drawImage(Canvas.canvas, SX, SY, WIDTH, HEIGHT, DX, DY, WIDTH, HEIGHT);
+ }
+
+ obj.SendUnPause = function () {
+ //obj.Debug("SendUnPause");
+ //obj.xxStateChange(3);
+ obj.send(String.fromCharCode(0x00, 0x08, 0x00, 0x05, 0x00));
+ }
+
+ obj.SendPause = function () {
+ //obj.Debug("SendPause");
+ //obj.xxStateChange(2);
+ obj.send(String.fromCharCode(0x00, 0x08, 0x00, 0x05, 0x01));
+ }
+
+ obj.SendCompressionLevel = function (type, level, scaling, frametimer) {
+ if (level) { obj.CompressionLevel = level; }
+ if (scaling) { obj.ScalingLevel = scaling; }
+ if (frametimer) { obj.FrameRateTimer = frametimer; }
+ obj.send(String.fromCharCode(0x00, 0x05, 0x00, 0x0A, type, obj.CompressionLevel) + obj.shortToStr(obj.ScalingLevel) + obj.shortToStr(obj.FrameRateTimer));
+ }
+
+ obj.SendRefresh = function () {
+ obj.send(String.fromCharCode(0x00, 0x06, 0x00, 0x04));
+ }
+
+ obj.ProcessScreenMsg = function (width, height) {
+ if (obj.debugmode > 0) { console.log("ScreenSize: " + width + " x " + height); }
+ obj.Canvas.setTransform(1, 0, 0, 1, 0, 0);
+ obj.rotation = 0;
+ obj.FirstDraw = true;
+ obj.ScreenWidth = obj.width = width;
+ obj.ScreenHeight = obj.height = height;
+ obj.KillDraw = obj.tilesReceived;
+ while (obj.PendingOperations.length > 0) { obj.PendingOperations.shift(); }
+ obj.SendCompressionLevel(1);
+ obj.SendUnPause();
+ if (obj.onScreenSizeChange != null) { obj.onScreenSizeChange(obj, obj.ScreenWidth, obj.ScreenHeight, obj.CanvasId); }
+ }
+
+ obj.ProcessData = function (str) {
+ var ptr = 0;
+ //console.log('x0', str.length);
+ while (ptr < str.length) {
+ //console.log('x1', ptr, str.length);
+ ptr += obj.ProcessDataEx(str.substring(ptr));
+ //console.log('x2', ptr, str.length);
+ }
+ }
+
+ obj.ProcessDataEx = function (str) {
+ if (obj.accumulator != null) {
+ str = obj.accumulator + str;
+ //console.log('KVM using accumulated data, total size is now ' + str.length + ' bytes.');
+ obj.accumulator = null;
+ }
+ if (obj.debugmode > 1) { console.log("KRecv(" + str.length + "): " + rstr2hex(str.substring(0, Math.min(str.length, 40)))); }
+ if (str.length < 4) return;
+ var cmdmsg = null, X = 0, Y = 0, command = ReadShort(str, 0), cmdsize = ReadShort(str, 2), jumboAdd = 0;
+ if ((command == 27) && (cmdsize == 8)) {
+ // Jumbo packet
+ if (str.length < 12) return;
+ command = ReadShort(str, 8)
+ cmdsize = ReadInt(str, 4);
+ //console.log('JUMBO cmd=' + command + ', cmdsize=' + cmdsize + ', data received=' + str.length);
+ if ((cmdsize + 8) > str.length) {
+ //console.log('KVM accumulator set to ' + str.length + ' bytes, need ' + cmdsize + ' bytes.');
+ obj.accumulator = str;
+ return;
+ }
+ str = str.substring(8);
+ jumboAdd = 8;
+ }
+ if ((cmdsize != str.length) && (obj.debugmode > 0)) { console.log(cmdsize, str.length, cmdsize == str.length); }
+ if ((command >= 18) && (command != 65)) { console.error("Invalid KVM command " + command + " of size " + cmdsize); console.log("Invalid KVM data", str.length, rstr2hex(str.substring(0, 40)) + '...'); return; }
+ if (cmdsize > str.length) {
+ //console.log('KVM accumulator set to ' + str.length + ' bytes, need ' + cmdsize + ' bytes.');
+ obj.accumulator = str;
+ return;
+ }
+ //console.log("KVM Command: " + command + " Len:" + cmdsize);
+
+ if (command == 3 || command == 4 || command == 7) {
+ cmdmsg = str.substring(4, cmdsize);
+ X = ((cmdmsg.charCodeAt(0) & 0xFF) << 8) + (cmdmsg.charCodeAt(1) & 0xFF);
+ Y = ((cmdmsg.charCodeAt(2) & 0xFF) << 8) + (cmdmsg.charCodeAt(3) & 0xFF);
+ if (obj.debugmode > 0) { console.log("CMD" + command + " at X=" + X + " Y=" + Y); }
+ }
+
+ switch (command) {
+ case 3: // Tile
+ if (obj.FirstDraw) obj.onResize();
+ obj.ProcessPictureMsg(cmdmsg, X, Y);
+ break;
+ case 4: // Tile Copy
+ if (obj.FirstDraw) obj.onResize();
+ if (obj.TilesDrawn == obj.tilesReceived) {
+ obj.ProcessCopyRectMsg(cmdmsg);
+ } else {
+ obj.PendingOperations.push([ ++tilesReceived, 1, cmdmsg ]);
+ }
+ break;
+ case 7: // Screen size
+ obj.ProcessScreenMsg(X, Y);
+ obj.SendKeyMsgKC(obj.KeyAction.UP, 16); // Shift
+ obj.SendKeyMsgKC(obj.KeyAction.UP, 17); // Ctrl
+ obj.SendKeyMsgKC(obj.KeyAction.UP, 18); // Alt
+ obj.SendKeyMsgKC(obj.KeyAction.UP, 91); // Left-Windows
+ obj.SendKeyMsgKC(obj.KeyAction.UP, 92); // Right-Windows
+ obj.SendKeyMsgKC(obj.KeyAction.UP, 16); // Shift
+ obj.send(String.fromCharCode(0x00, 0x0E, 0x00, 0x04));
+ break;
+ case 11: // GetDisplays
+ var selectedDisplay = 0, displays = { }, dcount = ((str.charCodeAt(4) & 0xFF) << 8) + (str.charCodeAt(5) & 0xFF);
+ if (dcount > 0) {
+ // Many displays present
+ selectedDisplay = ((str.charCodeAt(6 + (dcount * 2)) & 0xFF) << 8) + (str.charCodeAt(7 + (dcount * 2)) & 0xFF);
+ for (var i = 0; i < dcount; i++) {
+ var disp = ((str.charCodeAt(6 + (i * 2)) & 0xFF) << 8) + (str.charCodeAt(7 + (i * 2)) & 0xFF);
+ if (disp == 65535) { displays[disp] = 'All Displays'; } else { displays[disp] = 'Display ' + disp; }
+ }
+ }
+ //console.log('Get Displays', displays, selectedDisplay, rstr2hex(str));
+ if (obj.onDisplayinfo != null) { obj.onDisplayinfo(obj, displays, selectedDisplay); }
+ break;
+ case 12: // SetDisplay
+ //console.log('SetDisplayConfirmed');
+ break;
+ case 14: // KVM_INIT_TOUCH
+ obj.touchenabled = 1;
+ obj.TouchArray = {};
+ if (obj.onTouchEnabledChanged != null) obj.onTouchEnabledChanged(obj.touchenabled);
+ break;
+ case 15: // KVM_TOUCH
+ obj.TouchArray = {};
+ break;
+ case 16: // MNG_KVM_CONNECTCOUNT
+ obj.connectioncount = ReadInt(str, 4);
+ //obj.Debug("Got KVM Connect Count: " + obj.connectioncount);
+ if (obj.onConnectCountChanged != null) obj.onConnectCountChanged(obj.connectioncount, obj);
+ break;
+ case 17: // MNG_KVM_MESSAGE
+ //obj.Debug("Got KVM Message: " + str.substring(4, cmdsize));
+ if (obj.onMessage != null) obj.onMessage(str.substring(4, cmdsize), obj);
+ break;
+ case 65: // Alert
+ str = str.substring(4);
+ if (str[0] != '.') {
+ console.log(str); //alert('KVM: ' + str);
+ if (obj.parent != null) {
+ obj.parent.consoleMessage = str;
+ if (obj.parent.onConsoleMessageChange) { obj.parent.onConsoleMessageChange(obj.parent, str); }
+ }
+ } else {
+ console.log('KVM: ' + str.substring(1));
+ }
+ break;
+ }
+ return cmdsize + jumboAdd;
+ }
+
+ // Keyboard and Mouse I/O.
+ obj.MouseButton = { "NONE": 0x00, "LEFT": 0x02, "RIGHT": 0x08, "MIDDLE": 0x20 };
+ obj.KeyAction = { "NONE": 0, "DOWN": 1, "UP": 2, "SCROLL": 3, "EXUP": 4, "EXDOWN": 5, "DBLCLICK": 6 };
+ obj.InputType = { "KEY": 1, "MOUSE": 2, "CTRLALTDEL": 10, "TOUCH": 15 };
+ obj.Alternate = 0;
+
+ var convertKeyCodeTable = {
+ "Pause": 19,
+ "CapsLock": 20,
+ "Space": 32,
+ "Quote": 222,
+ "Minus": 189,
+ "NumpadMultiply": 106,
+ "NumpadAdd": 107,
+ "PrintScreen": 44,
+ "Comma": 188,
+ "NumpadSubtract": 109,
+ "NumpadDecimal": 110,
+ "Period": 190,
+ "Slash": 191,
+ "NumpadDivide": 111,
+ "Semicolon": 186,
+ "Equal": 187,
+ "OSLeft": 91,
+ "BracketLeft": 219,
+ "OSRight": 91,
+ "Backslash": 220,
+ "BracketRight": 221,
+ "ContextMenu": 93,
+ "Backquote": 192,
+ "NumLock": 144,
+ "ScrollLock": 145,
+ "Backspace": 8,
+ "Tab": 9,
+ "Enter": 13,
+ "NumpadEnter": 13,
+ "Escape": 27,
+ "Delete": 46,
+ "Home": 36,
+ "PageUp": 33,
+ "PageDown": 34,
+ "ArrowLeft": 37,
+ "ArrowUp": 38,
+ "ArrowRight": 39,
+ "ArrowDown": 40,
+ "End": 35,
+ "Insert": 45,
+ "F1": 112,
+ "F2": 113,
+ "F3": 114,
+ "F4": 115,
+ "F5": 116,
+ "F6": 117,
+ "F7": 118,
+ "F8": 119,
+ "F9": 120,
+ "F10": 121,
+ "F11": 122,
+ "F12": 123,
+ "ShiftLeft": 16,
+ "ShiftRight": 16,
+ "ControlLeft": 17,
+ "ControlRight": 17,
+ "AltLeft": 18,
+ "AltRight": 18,
+ "MetaLeft": 91,
+ "MetaRight": 92,
+ "VolumeMute": 181
+ //"LaunchMail":
+ //"LaunchApp1":
+ //"LaunchApp2":
+ //"BrowserStop":
+ //"MediaStop":
+ //"MediaTrackPrevious":
+ //"MediaTrackNext":
+ //"MediaPlayPause":
+ //"MediaSelect":
+ }
+
+ function convertKeyCode(e) {
+ if (e.code.startsWith('Key') && e.code.length == 4) { return e.code.charCodeAt(3); }
+ if (e.code.startsWith('Digit') && e.code.length == 6) { return e.code.charCodeAt(5); }
+ if (e.code.startsWith('Numpad') && e.code.length == 7) { return e.code.charCodeAt(6) + 48; }
+ return convertKeyCodeTable[e.code];
+ }
+
+ obj.SendKeyMsg = function (action, event) {
+ if (action == null) return;
+ if (!event) { event = window.event; }
+ if (event.code && (obj.localKeyMap == false)) {
+ // Convert "event.code" into a scancode. This works the same regardless of the keyboard language.
+ // Older browsers will not support this.
+ var kc = convertKeyCode(event);
+ if (kc != null) { obj.SendKeyMsgKC(action, kc); }
+ } else {
+ // Use this keycode, this works best with "US-EN" keyboards.
+ // Older browser support this.
+ var kc = event.keyCode;
+ if (kc == 0x3B) { kc = 0xBA; } // Fix the ';' key
+ else if (kc == 173) { kc = 189; } // Fix the '-' key for Firefox
+ else if (kc == 61) { kc = 187; } // Fix the '=' key for Firefox
+ obj.SendKeyMsgKC(action, kc);
+ }
+ }
+
+ obj.SendMessage = function (msg) {
+ if (obj.State == 3) obj.send(String.fromCharCode(0x00, 0x11) + obj.shortToStr(4 + msg.length) + msg); // 0x11 = 17 MNG_KVM_MESSAGE
+ }
+
+ obj.SendKeyMsgKC = function (action, kc) {
+ //console.log('SendKeyMsgKC', action, kc);
+ if (obj.State != 3) return;
+ if (typeof action == 'object') { for (var i in action) { obj.SendKeyMsgKC(action[i][0], action[i][1]); } }
+ else { obj.send(String.fromCharCode(0x00, obj.InputType.KEY, 0x00, 0x06, (action - 1), kc)); }
+ }
+
+ obj.sendcad = function() { obj.SendCtrlAltDelMsg(); }
+
+ obj.SendCtrlAltDelMsg = function () {
+ if (obj.State == 3) { obj.send(String.fromCharCode(0x00, obj.InputType.CTRLALTDEL, 0x00, 0x04)); }
+ }
+
+ obj.SendEscKey = function () {
+ if (obj.State == 3) obj.send(String.fromCharCode(0x00, obj.InputType.KEY, 0x00, 0x06, 0x00, 0x1B, 0x00, obj.InputType.KEY, 0x00, 0x06, 0x01, 0x1B));
+ }
+
+ obj.SendStartMsg = function () {
+ obj.SendKeyMsgKC(obj.KeyAction.EXDOWN, 0x5B); // L-Windows
+ obj.SendKeyMsgKC(obj.KeyAction.EXUP, 0x5B); // L-Windows
+ }
+
+ obj.SendCharmsMsg = function () {
+ obj.SendKeyMsgKC(obj.KeyAction.EXDOWN, 0x5B); // L-Windows
+ obj.SendKeyMsgKC(obj.KeyAction.DOWN, 67); // C
+ obj.SendKeyMsgKC(obj.KeyAction.UP, 67); // C
+ obj.SendKeyMsgKC(obj.KeyAction.EXUP, 0x5B); // L-Windows
+ }
+
+ obj.SendTouchMsg1 = function (id, flags, x, y) {
+ if (obj.State == 3) obj.send(String.fromCharCode(0x00, obj.InputType.TOUCH) + obj.shortToStr(14) + String.fromCharCode(0x01, id) + obj.intToStr(flags) + obj.shortToStr(x) + obj.shortToStr(y));
+ }
+
+ obj.SendTouchMsg2 = function (id, flags) {
+ var msg = '';
+ var flags2;
+ var str = "TOUCHSEND: ";
+ for (var k in obj.TouchArray) {
+ if (k == id) { flags2 = flags; } else {
+ if (obj.TouchArray[k].f == 1) { flags2 = 0x00010000 | 0x00000002 | 0x00000004; obj.TouchArray[k].f = 3; str += "START" + k; } // POINTER_FLAG_DOWN
+ else if (obj.TouchArray[k].f == 2) { flags2 = 0x00040000; str += "STOP" + k; } // POINTER_FLAG_UP
+ else flags2 = 0x00000002 | 0x00000004 | 0x00020000; // POINTER_FLAG_UPDATE
+ }
+ msg += String.fromCharCode(k) + obj.intToStr(flags2) + obj.shortToStr(obj.TouchArray[k].x) + obj.shortToStr(obj.TouchArray[k].y);
+ if (obj.TouchArray[k].f == 2) delete obj.TouchArray[k];
+ }
+ if (obj.State == 3) obj.send(String.fromCharCode(0x00, obj.InputType.TOUCH) + obj.shortToStr(5 + msg.length) + String.fromCharCode(0x02) + msg);
+ if (Object.keys(obj.TouchArray).length == 0 && obj.touchtimer != null) { clearInterval(obj.touchtimer); obj.touchtimer = null; }
+ }
+
+ obj.SendMouseMsg = function (Action, event) {
+ if (obj.State != 3) return;
+ if (Action != null && obj.Canvas != null) {
+ if (!event) { var event = window.event; }
+
+ var ScaleFactorHeight = (obj.Canvas.canvas.height / obj.CanvasId.clientHeight);
+ var ScaleFactorWidth = (obj.Canvas.canvas.width / obj.CanvasId.clientWidth);
+ var Offsets = obj.GetPositionOfControl(obj.Canvas.canvas);
+ var X = ((event.pageX - Offsets[0]) * ScaleFactorWidth);
+ var Y = ((event.pageY - Offsets[1]) * ScaleFactorHeight);
+ if (event.addx) { X += event.addx; }
+ if (event.addy) { Y += event.addy; }
+
+ if (X >= 0 && X <= obj.Canvas.canvas.width && Y >= 0 && Y <= obj.Canvas.canvas.height) {
+ var Button = 0;
+ var Delta = 0;
+ if (Action == obj.KeyAction.UP || Action == obj.KeyAction.DOWN) {
+ if (event.which) { ((event.which == 1) ? (Button = obj.MouseButton.LEFT) : ((event.which == 2) ? (Button = obj.MouseButton.MIDDLE) : (Button = obj.MouseButton.RIGHT))); }
+ else if (event.button) { ((event.button == 0) ? (Button = obj.MouseButton.LEFT) : ((event.button == 1) ? (Button = obj.MouseButton.MIDDLE) : (Button = obj.MouseButton.RIGHT))); }
+ }
+ else if (Action == obj.KeyAction.SCROLL) {
+ if (event.detail) { Delta = (-1 * (event.detail * 120)); } else if (event.wheelDelta) { Delta = (event.wheelDelta * 3); }
+ }
+
+ var MouseMsg = "";
+ if (Action == obj.KeyAction.DBLCLICK) {
+ MouseMsg = String.fromCharCode(0x00, obj.InputType.MOUSE, 0x00, 0x0A, 0x00, 0x88, ((X / 256) & 0xFF), (X & 0xFF), ((Y / 256) & 0xFF), (Y & 0xFF));
+ } else if (Action == obj.KeyAction.SCROLL) {
+ MouseMsg = String.fromCharCode(0x00, obj.InputType.MOUSE, 0x00, 0x0C, 0x00, 0x00, ((X / 256) & 0xFF), (X & 0xFF), ((Y / 256) & 0xFF), (Y & 0xFF), ((Delta / 256) & 0xFF), (Delta & 0xFF));
+ } else {
+ MouseMsg = String.fromCharCode(0x00, obj.InputType.MOUSE, 0x00, 0x0A, 0x00, ((Action == obj.KeyAction.DOWN) ? Button : ((Button * 2) & 0xFF)), ((X / 256) & 0xFF), (X & 0xFF), ((Y / 256) & 0xFF), (Y & 0xFF));
+ }
+
+ if (obj.Action == obj.KeyAction.NONE) {
+ if (obj.Alternate == 0 || obj.ipad) { obj.send(MouseMsg); obj.Alternate = 1; } else { obj.Alternate = 0; }
+ } else {
+ obj.send(MouseMsg);
+ }
+ }
+ }
+ }
+
+ obj.GetDisplayNumbers = function () { obj.send(String.fromCharCode(0x00, 0x0B, 0x00, 0x04)); } // Get Terminal display
+ obj.SetDisplay = function (number) { console.log('Set display', number); obj.send(String.fromCharCode(0x00, 0x0C, 0x00, 0x06, number >> 8, number & 0xFF)); } // Set Terminal display
+ obj.intToStr = function (x) { return String.fromCharCode((x >> 24) & 0xFF, (x >> 16) & 0xFF, (x >> 8) & 0xFF, x & 0xFF); }
+ obj.shortToStr = function (x) { return String.fromCharCode((x >> 8) & 0xFF, x & 0xFF); }
+
+ obj.onResize = function () {
+ if (obj.ScreenWidth == 0 || obj.ScreenHeight == 0) return;
+ if (obj.Canvas.canvas.width == obj.ScreenWidth && obj.Canvas.canvas.height == obj.ScreenHeight) return;
+ if (obj.FirstDraw) {
+ obj.Canvas.canvas.width = obj.ScreenWidth;
+ obj.Canvas.canvas.height = obj.ScreenHeight;
+ obj.Canvas.fillRect(0, 0, obj.ScreenWidth, obj.ScreenHeight);
+ if (obj.onScreenSizeChange != null) obj.onScreenSizeChange(obj, obj.ScreenWidth, obj.ScreenHeight, obj.CanvasId);
+ }
+ obj.FirstDraw = false;
+ //obj.Debug("onResize: " + obj.ScreenWidth + " x " + obj.ScreenHeight);
+ }
+
+ obj.xxMouseInputGrab = false;
+ obj.xxKeyInputGrab = false;
+ obj.xxMouseMove = function (e) { if (obj.State == 3) obj.SendMouseMsg(obj.KeyAction.NONE, e); if (e.preventDefault) e.preventDefault(); if (e.stopPropagation) e.stopPropagation(); return false; }
+ obj.xxMouseUp = function (e) { if (obj.State == 3) obj.SendMouseMsg(obj.KeyAction.UP, e); if (e.preventDefault) e.preventDefault(); if (e.stopPropagation) e.stopPropagation(); return false; }
+ obj.xxMouseDown = function (e) { if (obj.State == 3) obj.SendMouseMsg(obj.KeyAction.DOWN, e); if (e.preventDefault) e.preventDefault(); if (e.stopPropagation) e.stopPropagation(); return false; }
+ obj.xxMouseDblClick = function (e) { if (obj.State == 3) obj.SendMouseMsg(obj.KeyAction.DBLCLICK, e); if (e.preventDefault) e.preventDefault(); if (e.stopPropagation) e.stopPropagation(); return false; }
+ obj.xxDOMMouseScroll = function (e) { if (obj.State == 3) { obj.SendMouseMsg(obj.KeyAction.SCROLL, e); return false; } return true; }
+ obj.xxMouseWheel = function (e) { if (obj.State == 3) { obj.SendMouseMsg(obj.KeyAction.SCROLL, e); return false; } return true; }
+ obj.xxKeyUp = function (e) { if (obj.State == 3) { obj.SendKeyMsg(obj.KeyAction.UP, e); } if (e.preventDefault) e.preventDefault(); if (e.stopPropagation) e.stopPropagation(); return false; }
+ obj.xxKeyDown = function (e) { if (obj.State == 3) { obj.SendKeyMsg(obj.KeyAction.DOWN, e); } if (e.preventDefault) e.preventDefault(); if (e.stopPropagation) e.stopPropagation(); return false; }
+ obj.xxKeyPress = function (e) { if (e.preventDefault) e.preventDefault(); if (e.stopPropagation) e.stopPropagation(); return false; }
+
+ // Key handlers
+ obj.handleKeys = function (e) { if (obj.stopInput == true || desktop.State != 3) return false; return obj.xxKeyPress(e); }
+ obj.handleKeyUp = function (e) {
+ if (obj.stopInput == true || desktop.State != 3) return false;
+ if (obj.firstUpKeys.length < 5) {
+ obj.firstUpKeys.push(e.keyCode);
+ if ((obj.firstUpKeys.length == 5)) { var j = obj.firstUpKeys.join(','); if ((j == '16,17,91,91,16') || (j == '16,17,18,91,92')) { obj.stopInput = true; } }
+ }
+ if (e.keyCode == 16) { obj.shiftPressed = false; }
+ if (e.keyCode == 17) { obj.ctrlPressed = false; }
+ if (e.keyCode == 18) { obj.altPressed = false; }
+ return obj.xxKeyUp(e);
+ }
+ obj.handleKeyDown = function (e) {
+ if (obj.stopInput == true || desktop.State != 3) return false;
+ if (e.keyCode == 16) { obj.shiftPressed = true; }
+ if (e.keyCode == 17) { obj.ctrlPressed = true; }
+ if (e.keyCode == 18) { obj.altPressed = true; }
+ return obj.xxKeyDown(e);
+ }
+
+ // Release the CTRL, ALT, SHIFT keys if they are pressed.
+ obj.handleReleaseKeys = function () {
+ if (obj.shiftPressed) { obj.SendKeyMsgKC(obj.KeyAction.UP, 16); } // Shift
+ if (obj.ctrlPressed) { obj.SendKeyMsgKC(obj.KeyAction.UP, 17); } // Ctrl
+ if (obj.altPressed) { obj.SendKeyMsgKC(obj.KeyAction.UP, 18); } // Alt
+ obj.shiftPressed = obj.ctrlPressed = obj.altPressed = false;
+ }
+
+ // Mouse handlers
+ obj.mousedblclick = function (e) { if (obj.stopInput == true) return false; return obj.xxMouseDblClick(e); }
+ obj.mousedown = function (e) { if (obj.stopInput == true) return false; return obj.xxMouseDown(e); }
+ obj.mouseup = function (e) { if (obj.stopInput == true) return false; return obj.xxMouseUp(e); }
+ obj.mousemove = function (e) { if (obj.stopInput == true) return false; return obj.xxMouseMove(e); }
+ obj.mousewheel = function (e) { if (obj.stopInput == true) return false; return obj.xxMouseWheel(e); }
+
+ obj.xxMsTouchEvent = function (evt) {
+ if (evt.originalEvent.pointerType == 4) return; // If this is a mouse pointer, ignore this event. Touch & pen are ok.
+ if (evt.preventDefault) evt.preventDefault();
+ if (evt.stopPropagation) evt.stopPropagation();
+ if (evt.type == 'MSPointerDown' || evt.type == 'MSPointerMove' || evt.type == 'MSPointerUp') {
+ var flags = 0;
+ var id = evt.originalEvent.pointerId % 256;
+ var X = evt.offsetX * (Canvas.canvas.width / obj.CanvasId.clientWidth);
+ var Y = evt.offsetY * (Canvas.canvas.height / obj.CanvasId.clientHeight);
+
+ if (evt.type == 'MSPointerDown') flags = 0x00010000 | 0x00000002 | 0x00000004; // POINTER_FLAG_DOWN
+ else if (evt.type == 'MSPointerMove') {
+ //if (obj.TouchArray[id] && MuchTheSame(obj.TouchArray[id].x, X) && MuchTheSame(obj.TouchArray[id].y, Y)) return;
+ flags = 0x00020000 | 0x00000002 | 0x00000004; // POINTER_FLAG_UPDATE
+ }
+ else if (evt.type == 'MSPointerUp') flags = 0x00040000; // POINTER_FLAG_UP
+
+ if (!obj.TouchArray[id]) obj.TouchArray[id] = { x: X, y : Y };
+ obj.SendTouchMsg2(id, flags)
+ if (evt.type == 'MSPointerUp') delete obj.TouchArray[id];
+ } else {
+ alert(evt.type);
+ }
+ return true;
+ }
+
+ obj.xxTouchStart = function (e) {
+ if (obj.State != 3) return;
+ if (e.preventDefault) e.preventDefault();
+ if (obj.touchenabled == 0 || obj.touchenabled == 1) {
+ if (e.originalEvent.touches.length > 1) return;
+ var t = e.originalEvent.touches[0];
+ e.which = 1;
+ obj.LastX = e.pageX = t.pageX;
+ obj.LastY = e.pageY = t.pageY;
+ obj.SendMouseMsg(KeyAction.DOWN, e);
+ } else {
+ var Offsets = obj.GetPositionOfControl(Canvas.canvas);
+ for (var i in e.originalEvent.changedTouches) {
+ if (!e.originalEvent.changedTouches[i].identifier) continue;
+ var id = e.originalEvent.changedTouches[i].identifier % 256;
+ if (!obj.TouchArray[id]) { obj.TouchArray[id] = { x: (e.originalEvent.touches[i].pageX - Offsets[0]) * (Canvas.canvas.width / obj.CanvasId.clientWidth), y: (e.originalEvent.touches[i].pageY - Offsets[1]) * (Canvas.canvas.height / obj.CanvasId.clientHeight), f: 1 }; }
+ }
+ if (Object.keys(obj.TouchArray).length > 0 && touchtimer == null) { obj.touchtimer = setInterval(function () { obj.SendTouchMsg2(256, 0); }, 50); }
+ }
+ }
+
+ obj.xxTouchMove = function (e) {
+ if (obj.State != 3) return;
+ if (e.preventDefault) e.preventDefault();
+ if (obj.touchenabled == 0 || obj.touchenabled == 1) {
+ if (e.originalEvent.touches.length > 1) return;
+ var t = e.originalEvent.touches[0];
+ e.which = 1;
+ obj.LastX = e.pageX = t.pageX;
+ obj.LastY = e.pageY = t.pageY;
+ obj.SendMouseMsg(obj.KeyAction.NONE, e);
+ } else {
+ var Offsets = obj.GetPositionOfControl(Canvas.canvas);
+ for (var i in e.originalEvent.changedTouches) {
+ if (!e.originalEvent.changedTouches[i].identifier) continue;
+ var id = e.originalEvent.changedTouches[i].identifier % 256;
+ if (obj.TouchArray[id]) {
+ obj.TouchArray[id].x = (e.originalEvent.touches[i].pageX - Offsets[0]) * (obj.Canvas.canvas.width / obj.CanvasId.clientWidth);
+ obj.TouchArray[id].y = (e.originalEvent.touches[i].pageY - Offsets[1]) * (obj.Canvas.canvas.height / obj.CanvasId.clientHeight);
+ }
+ }
+ }
+ }
+
+ obj.xxTouchEnd = function (e) {
+ if (obj.State != 3) return;
+ if (e.preventDefault) e.preventDefault();
+ if (obj.touchenabled == 0 || obj.touchenabled == 1) {
+ if (e.originalEvent.touches.length > 1) return;
+ e.which = 1;
+ e.pageX = LastX;
+ e.pageY = LastY;
+ obj.SendMouseMsg(KeyAction.UP, e);
+ } else {
+ for (var i in e.originalEvent.changedTouches) {
+ if (!e.originalEvent.changedTouches[i].identifier) continue;
+ var id = e.originalEvent.changedTouches[i].identifier % 256;
+ if (obj.TouchArray[id]) obj.TouchArray[id].f = 2;
+ }
+ }
+ }
+
+ obj.GrabMouseInput = function () {
+ if (obj.xxMouseInputGrab == true) return;
+ var c = obj.CanvasId;
+ c.onmousemove = obj.xxMouseMove;
+ c.onmouseup = obj.xxMouseUp;
+ c.onmousedown = obj.xxMouseDown;
+ c.touchstart = obj.xxTouchStart;
+ c.touchmove = obj.xxTouchMove;
+ c.touchend = obj.xxTouchEnd;
+ c.MSPointerDown = obj.xxMsTouchEvent;
+ c.MSPointerMove = obj.xxMsTouchEvent;
+ c.MSPointerUp = obj.xxMsTouchEvent;
+ if (navigator.userAgent.match(/mozilla/i)) c.DOMMouseScroll = obj.xxDOMMouseScroll; else c.onmousewheel = obj.xxMouseWheel;
+ obj.xxMouseInputGrab = true;
+ }
+
+ obj.UnGrabMouseInput = function () {
+ if (obj.xxMouseInputGrab == false) return;
+ var c = obj.CanvasId;
+ c.onmousemove = null;
+ c.onmouseup = null;
+ c.onmousedown = null;
+ c.touchstart = null;
+ c.touchmove = null;
+ c.touchend = null;
+ c.MSPointerDown = null;
+ c.MSPointerMove = null;
+ c.MSPointerUp = null;
+ if (navigator.userAgent.match(/mozilla/i)) c.DOMMouseScroll = null; else c.onmousewheel = null;
+ obj.xxMouseInputGrab = false;
+ }
+
+ obj.GrabKeyInput = function () {
+ if (obj.xxKeyInputGrab == true) return;
+ document.onkeyup = obj.xxKeyUp;
+ document.onkeydown = obj.xxKeyDown;
+ document.onkeypress = obj.xxKeyPress;
+ obj.xxKeyInputGrab = true;
+ }
+
+ obj.UnGrabKeyInput = function () {
+ if (obj.xxKeyInputGrab == false) return;
+ document.onkeyup = null;
+ document.onkeydown = null;
+ document.onkeypress = null;
+ obj.xxKeyInputGrab = false;
+ }
+
+ obj.GetPositionOfControl = function (Control) {
+ var Position = Array(2);
+ Position[0] = Position[1] = 0;
+ while (Control) { Position[0] += Control.offsetLeft; Position[1] += Control.offsetTop; Control = Control.offsetParent; }
+ return Position;
+ }
+
+ obj.crotX = function (x, y) {
+ if (obj.rotation == 0) return x;
+ if (obj.rotation == 1) return y;
+ if (obj.rotation == 2) return obj.Canvas.canvas.width - x;
+ if (obj.rotation == 3) return obj.Canvas.canvas.height - y;
+ }
+
+ obj.crotY = function (x, y) {
+ if (obj.rotation == 0) return y;
+ if (obj.rotation == 1) return obj.Canvas.canvas.width - x;
+ if (obj.rotation == 2) return obj.Canvas.canvas.height - y;
+ if (obj.rotation == 3) return x;
+ }
+
+ obj.rotX = function (x, y) {
+ if (obj.rotation == 0 || obj.rotation == 1) return x;
+ if (obj.rotation == 2) return x - obj.Canvas.canvas.width;
+ if (obj.rotation == 3) return x - obj.Canvas.canvas.height;
+ }
+
+ obj.rotY = function (x, y) {
+ if (obj.rotation == 0 || obj.rotation == 3) return y;
+ if (obj.rotation == 1) return y - obj.Canvas.canvas.width;
+ if (obj.rotation == 2) return y - obj.Canvas.canvas.height;
+ }
+
+ obj.tcanvas = null;
+ obj.setRotation = function (x) {
+ while (x < 0) { x += 4; }
+ var newrotation = x % 4;
+ if (newrotation == obj.rotation) return true;
+ var rw = obj.Canvas.canvas.width;
+ var rh = obj.Canvas.canvas.height;
+ if (obj.rotation == 1 || obj.rotation == 3) { rw = obj.Canvas.canvas.height; rh = obj.Canvas.canvas.width; }
+
+ // Copy the canvas, put it back in the correct direction
+ if (obj.tcanvas == null) obj.tcanvas = document.createElement('canvas');
+ var tcanvasctx = obj.tcanvas.getContext('2d');
+ tcanvasctx.setTransform(1, 0, 0, 1, 0, 0);
+ tcanvasctx.canvas.width = rw;
+ tcanvasctx.canvas.height = rh;
+ tcanvasctx.rotate((obj.rotation * -90) * Math.PI / 180);
+ if (obj.rotation == 0) tcanvasctx.drawImage(obj.Canvas.canvas, 0, 0);
+ if (obj.rotation == 1) tcanvasctx.drawImage(obj.Canvas.canvas, -obj.Canvas.canvas.width, 0);
+ if (obj.rotation == 2) tcanvasctx.drawImage(obj.Canvas.canvas, -obj.Canvas.canvas.width, -obj.Canvas.canvas.height);
+ if (obj.rotation == 3) tcanvasctx.drawImage(obj.Canvas.canvas, 0, -obj.Canvas.canvas.height);
+
+ // Change the size and orientation and copy the canvas back into the rotation
+ if (obj.rotation == 0 || obj.rotation == 2) { obj.Canvas.canvas.height = rw; obj.Canvas.canvas.width = rh; }
+ if (obj.rotation == 1 || obj.rotation == 3) { obj.Canvas.canvas.height = rh; obj.Canvas.canvas.width = rw; }
+ obj.Canvas.setTransform(1, 0, 0, 1, 0, 0);
+ obj.Canvas.rotate((newrotation * 90) * Math.PI / 180);
+ obj.rotation = newrotation;
+ obj.Canvas.drawImage(obj.tcanvas, obj.rotX(0, 0), obj.rotY(0, 0));
+
+ obj.ScreenWidth = obj.Canvas.canvas.width;
+ obj.ScreenHeight = obj.Canvas.canvas.height;
+ if (obj.onScreenSizeChange != null) obj.onScreenSizeChange(obj, obj.ScreenWidth, obj.ScreenHeight, obj.CanvasId);
+ return true;
+ }
+
+ // Private method
+ obj.MuchTheSame = function (a, b) { return (Math.abs(a - b) < 4); }
+ obj.Debug = function (msg) { console.log(msg); }
+ obj.getIEVersion = function () { var r = -1; if (navigator.appName == 'Microsoft Internet Explorer') { var ua = navigator.userAgent; var re = new RegExp("MSIE ([0-9]{1,}[\.0-9]{0,})"); if (re.exec(ua) != null) r = parseFloat(RegExp.$1); } return r; }
+ obj.haltEvent = function (e) { if (e.preventDefault) e.preventDefault(); if (e.stopPropagation) e.stopPropagation(); return false; }
+
+ return obj;
+}
diff --git a/agent-redir-rtc-0.1.0.js b/agent-redir-rtc-0.1.0.js
new file mode 100644
index 0000000..fd60b27
--- /dev/null
+++ b/agent-redir-rtc-0.1.0.js
@@ -0,0 +1,145 @@
+/**
+* @description Mesh Agent Transport Module - using websocket relay
+* @author Ylian Saint-Hilaire
+* @version v0.0.1
+*/
+
+// Construct a MeshServer agent direction object
+var CreateKvmDataChannel = function (webchannel, module, keepalive) {
+ var obj = {};
+ obj.m = module; // This is the inner module (Terminal or Desktop)
+ module.parent = obj;
+ obj.webchannel = webchannel;
+ obj.State = 0;
+ obj.protocol = module.protocol; // 1 = SOL, 2 = KVM, 3 = IDER, 4 = Files, 5 = FileTransfer
+ obj.onStateChanged = null;
+ obj.onControlMsg = null;
+ obj.debugmode = 0;
+ obj.keepalive = keepalive;
+ obj.rtcKeepAlive = null;
+
+ // Private method
+ //obj.debug = function (msg) { console.log(msg); }
+
+ obj.Start = function () {
+ if (obj.debugmode == 1) { console.log('start'); }
+ obj.xxStateChange(3);
+ obj.webchannel.onmessage = obj.xxOnMessage;
+ obj.rtcKeepAlive = setInterval(obj.xxSendRtcKeepAlive, 30000);
+ }
+
+ // Setup the file reader
+ var fileReader = new FileReader();
+ var fileReaderInuse = false, fileReaderAcc = [];
+ if (fileReader.readAsBinaryString) {
+ // Chrome & Firefox (Draft)
+ fileReader.onload = function (e) { obj.xxOnSocketData(e.target.result); if (fileReaderAcc.length == 0) { fileReaderInuse = false; } else { fileReader.readAsBinaryString(new Blob([fileReaderAcc.shift()])); } }
+ } else if (fileReader.readAsArrayBuffer) {
+ // Chrome & Firefox (Spec)
+ fileReader.onloadend = function (e) { obj.xxOnSocketData(e.target.result); if (fileReaderAcc.length == 0) { fileReaderInuse = false; } else { fileReader.readAsArrayBuffer(fileReaderAcc.shift()); } }
+ }
+
+ obj.xxOnMessage = function (e) {
+ //if (obj.debugmode == 1) { console.log('Recv', e.data); }
+ //if (urlvars && urlvars['webrtctrace']) { console.log('WebRTC-Recv(' + obj.State + '): ', typeof e.data, e.data); }
+ if (typeof e.data == 'string') { if (obj.onControlMsg != null) { obj.onControlMsg(e.data); } return; } // If this is a control message, handle it here.
+ if (typeof e.data == 'object') {
+ if (fileReaderInuse == true) { fileReaderAcc.push(e.data); return; }
+ if (fileReader.readAsBinaryString) {
+ // Chrome & Firefox (Draft)
+ fileReaderInuse = true;
+ fileReader.readAsBinaryString(new Blob([e.data]));
+ } else if (f.readAsArrayBuffer) {
+ // Chrome & Firefox (Spec)
+ fileReaderInuse = true;
+ fileReader.readAsArrayBuffer(e.data);
+ } else {
+ // IE10, readAsBinaryString does not exist, use an alternative.
+ var binary = "", bytes = new Uint8Array(e.data), length = bytes.byteLength;
+ for (var i = 0; i < length; i++) { binary += String.fromCharCode(bytes[i]); }
+ obj.xxOnSocketData(binary);
+ }
+ } else {
+ // If we get a string object, it maybe the WebRTC confirm. Ignore it.
+ //obj.debug("Agent Redir Relay - OnData - " + typeof e.data + " - " + e.data.length);
+ obj.xxOnSocketData(e.data);
+ }
+ };
+
+ /*
+ obj.xxOnMessage = function (e) {
+ //if (obj.debugmode == 1) { console.log('Recv', e.data); }
+ if (urlvars && urlvars['webrtctrace']) { console.log('WebRTC-Recv(' + obj.State + '): ', typeof e.data, e.data); }
+ if (typeof e.data == 'string') { if (obj.onControlMsg != null) { obj.onControlMsg(e.data); } return; } // If this is a control message, handle it here.
+ if (typeof e.data == 'object') {
+ var f = new FileReader();
+ if (f.readAsBinaryString) {
+ // Chrome & Firefox (Draft)
+ f.onload = function (e) { obj.xxOnSocketData(e.target.result); }
+ f.readAsBinaryString(new Blob([e.data]));
+ } else if (f.readAsArrayBuffer) {
+ // Chrome & Firefox (Spec)
+ f.onloadend = function (e) { obj.xxOnSocketData(e.target.result); }
+ f.readAsArrayBuffer(e.data);
+ } else {
+ // IE10, readAsBinaryString does not exist, use an alternative.
+ var binary = '', bytes = new Uint8Array(e.data), length = bytes.byteLength;
+ for (var i = 0; i < length; i++) { binary += String.fromCharCode(bytes[i]); }
+ obj.xxOnSocketData(binary);
+ }
+ } else {
+ // If we get a string object, it maybe the WebRTC confirm. Ignore it.
+ //obj.debug("Agent Redir Relay - OnData - " + typeof e.data + " - " + e.data.length);
+ obj.xxOnSocketData(e.data);
+ }
+ };
+ */
+ obj.xxOnSocketData = function (data) {
+ if (!data) return;
+ if (typeof data === 'object') {
+ // This is an ArrayBuffer, convert it to a string array (used in IE)
+ var binary = "", bytes = new Uint8Array(data), length = bytes.byteLength;
+ for (var i = 0; i < length; i++) { binary += String.fromCharCode(bytes[i]); }
+ data = binary;
+ }
+ else if (typeof data !== 'string') return;
+ //console.log("xxOnSocketData", rstr2hex(data));
+ return obj.m.ProcessData(data);
+ }
+
+ // Send a control message over the WebRTC data channel
+ obj.sendCtrlMsg = function (x) {
+ if (typeof x == 'string') {
+ obj.webchannel.send(x);
+ if (urlvars && urlvars['webrtctrace']) { console.log('WebRTC-Send(' + obj.State + '): ', typeof x, x); }
+ if (obj.keepalive != null) obj.keepalive.sendKeepAlive();
+ }
+ }
+
+ // Send a binary message over the WebRTC data channel
+ obj.send = function (x) {
+ if (typeof x == 'string') { var b = new Uint8Array(x.length); for (var i = 0; i < x.length; ++i) { b[i] = x.charCodeAt(i); } x = b; }
+ if (urlvars && urlvars['webrtctrace']) { console.log('WebRTC-Send(' + obj.State + '): ', typeof x, x); }
+ obj.webchannel.send(x);
+ }
+
+ obj.xxStateChange = function(newstate) {
+ if (obj.State == newstate) return;
+ obj.State = newstate;
+ obj.m.xxStateChange(obj.State);
+ if (obj.onStateChanged != null) obj.onStateChanged(obj, obj.State);
+ }
+
+ obj.Stop = function () {
+ if (obj.debugmode == 1) { console.log('stop'); }
+ if (obj.rtcKeepAlive != null) { clearInterval(obj.rtcKeepAlive); obj.rtcKeepAlive = null; }
+ obj.xxStateChange(0);
+ }
+
+ obj.xxSendRtcKeepAlive = function () {
+ if (urlvars && urlvars['webrtctrace']) { console.log('WebRTC-SendKeepAlive()'); }
+ obj.sendCtrlMsg(JSON.stringify({ action: 'ping' }));
+ }
+
+ return obj;
+}
diff --git a/amt-0.2.0.js b/amt-0.2.0.js
new file mode 100644
index 0000000..76e9443
--- /dev/null
+++ b/amt-0.2.0.js
@@ -0,0 +1,987 @@
+/**
+* @fileoverview Intel(r) AMT Communication StackXX
+* @author Ylian Saint-Hilaire
+* @version v0.2.0b
+*/
+
+/**
+ * Construct a AmtStackCreateService object, this ia the main Intel AMT communication stack.
+ * @constructor
+ */
+function AmtStackCreateService(wsmanStack) {
+ var obj = new Object();
+ obj.wsman = wsmanStack;
+ obj.pfx = ["http://intel.com/wbem/wscim/1/amt-schema/1/", "http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/", "http://intel.com/wbem/wscim/1/ips-schema/1/"];
+ obj.PendingEnums = [];
+ obj.PendingBatchOperations = 0;
+ obj.ActiveEnumsCount = 0;
+ obj.MaxActiveEnumsCount = 1; // Maximum number of enumerations that can be done at the same time.
+ obj.onProcessChanged = null;
+ var _MaxProcess = 0;
+ var _LastProcess = 0;
+
+ // Return the number of pending actions
+ obj.GetPendingActions = function () { return (obj.PendingEnums.length * 2) + (obj.ActiveEnumsCount) + obj.wsman.comm.PendingAjax.length + obj.wsman.comm.ActiveAjaxCount + obj.PendingBatchOperations; }
+
+ // Private Method, Update the current processing status, this gives the application an idea of what progress is being done by the WSMAN stack
+ function _up() {
+ var x = obj.GetPendingActions();
+ if (_MaxProcess < x) _MaxProcess = x;
+ if (obj.onProcessChanged != null && _LastProcess != x) {
+ //console.log("Process Old=" + _LastProcess + ", New=" + x + ", PEnums=" + obj.PendingEnums.length + ", AEnums=" + obj.ActiveEnumsCount + ", PAjax=" + obj.wsman.comm.PendingAjax.length + ", AAjax=" + obj.wsman.comm.ActiveAjaxCount + ", PBatch=" + obj.PendingBatchOperations);
+ _LastProcess = x;
+ obj.onProcessChanged(x, _MaxProcess);
+ }
+ if (x == 0) _MaxProcess = 0;
+ }
+
+ // Perform a WSMAN "SUBSCRIBE" operation.
+ obj.Subscribe = function (name, delivery, url, callback, tag, pri, selectors, opaque, user, pass) { obj.wsman.ExecSubscribe(obj.CompleteName(name), delivery, url, function (ws, resuri, response, xstatus) { _up(); callback(obj, name, response, xstatus, tag); }, 0, pri, selectors, opaque, user, pass); _up(); }
+
+ // Perform a WSMAN "UNSUBSCRIBE" operation.
+ obj.UnSubscribe = function (name, callback, tag, pri, selectors) { obj.wsman.ExecUnSubscribe(obj.CompleteName(name), function (ws, resuri, response, xstatus) { _up(); callback(obj, name, response, xstatus, tag); }, 0, pri, selectors); _up(); }
+
+ // Perform a WSMAN "GET" operation.
+ obj.Get = function (name, callback, tag, pri) { obj.wsman.ExecGet(obj.CompleteName(name), function (ws, resuri, response, xstatus) { _up(); callback(obj, name, response, xstatus, tag); }, 0, pri); _up(); }
+
+ // Perform a WSMAN "PUT" operation.
+ obj.Put = function (name, putobj, callback, tag, pri, selectors) { obj.wsman.ExecPut(obj.CompleteName(name), putobj, function (ws, resuri, response, xstatus) { _up(); callback(obj, name, response, xstatus, tag); }, 0, pri, selectors); _up(); }
+
+ // Perform a WSMAN "CREATE" operation.
+ obj.Create = function (name, putobj, callback, tag, pri) { obj.wsman.ExecCreate(obj.CompleteName(name), putobj, function (ws, resuri, response, xstatus) { _up(); callback(obj, name, response, xstatus, tag); }, 0, pri); _up(); }
+
+ // Perform a WSMAN "DELETE" operation.
+ obj.Delete = function (name, putobj, callback, tag, pri) { obj.wsman.ExecDelete(obj.CompleteName(name), putobj, function (ws, resuri, response, xstatus) { _up(); callback(obj, name, response, xstatus, tag); }, 0, pri); _up(); }
+
+ // Perform a WSMAN method call operation.
+ obj.Exec = function (name, method, args, callback, tag, pri, selectors) { obj.wsman.ExecMethod(obj.CompleteName(name), method, args, function (ws, resuri, response, xstatus) { _up(); callback(obj, name, obj.CompleteExecResponse(response), xstatus, tag); }, 0, pri, selectors); _up(); }
+
+ // Perform a WSMAN method call operation.
+ obj.ExecWithXml = function (name, method, args, callback, tag, pri, selectors) { obj.wsman.ExecMethodXml(obj.CompleteName(name), method, execArgumentsToXml(args), function (ws, resuri, response, xstatus) { _up(); callback(obj, name, obj.CompleteExecResponse(response), xstatus, tag); }, 0, pri, selectors); _up(); }
+
+ // Perform a WSMAN "ENUMERATE" operation.
+ obj.Enum = function (name, callback, tag, pri) {
+ if (obj.ActiveEnumsCount < obj.MaxActiveEnumsCount) {
+ obj.ActiveEnumsCount++; obj.wsman.ExecEnum(obj.CompleteName(name), function (ws, resuri, response, xstatus, tag0) { _up(); _EnumStartSink(name, response, callback, resuri, xstatus, tag0); }, tag, pri);
+ } else {
+ obj.PendingEnums.push([name, callback, tag, pri]);
+ }
+ _up();
+ }
+
+ // Private method
+ function _EnumStartSink(name, response, callback, resuri, status, tag, pri) {
+ if (status != 200) { callback(obj, name, null, status, tag); _EnumDoNext(1); return; }
+ if (response == null || response.Header["Method"] != "EnumerateResponse" || !response.Body["EnumerationContext"]) { callback(obj, name, null, 603, tag); _EnumDoNext(1); return; }
+ var enumctx = response.Body["EnumerationContext"];
+ obj.wsman.ExecPull(resuri, enumctx, function (ws, resuri, response, xstatus) { _EnumContinueSink(name, response, callback, resuri, [], xstatus, tag, pri); });
+ }
+
+ // Private method
+ function _EnumContinueSink(name, response, callback, resuri, items, status, tag, pri) {
+ if (status != 200) { callback(obj, name, null, status, tag); _EnumDoNext(1); return; }
+ if (response == null || response.Header["Method"] != "PullResponse") { callback(obj, name, null, 604, tag); _EnumDoNext(1); return; }
+ for (var i in response.Body["Items"]) {
+ if (response.Body["Items"][i] instanceof Array) {
+ for (var j in response.Body["Items"][i]) { if (typeof response.Body["Items"][i][j] != 'function') { items.push(response.Body["Items"][i][j]); } }
+ } else {
+ if (typeof response.Body["Items"][i] != 'function') { items.push(response.Body["Items"][i]); }
+ }
+ }
+ if (response.Body["EnumerationContext"]) {
+ var enumctx = response.Body["EnumerationContext"];
+ obj.wsman.ExecPull(resuri, enumctx, function (ws, resuri, response, xstatus) { _EnumContinueSink(name, response, callback, resuri, items, xstatus, tag, 1); });
+ } else {
+ _EnumDoNext(1);
+ callback(obj, name, items, status, tag);
+ _up();
+ }
+ }
+
+ // Private method
+ function _EnumDoNext(dec) {
+ obj.ActiveEnumsCount -= dec;
+ if (obj.ActiveEnumsCount >= obj.MaxActiveEnumsCount || obj.PendingEnums.length == 0) { _up(); return; }
+ var x = obj.PendingEnums.shift();
+ obj.Enum(x[0], x[1], x[2]);
+ _EnumDoNext(0);
+ }
+
+ // Perform a batch of WSMAN "ENUM" operations.
+ obj.BatchEnum = function (batchname, names, callback, tag, continueOnError, pri) {
+ obj.PendingBatchOperations += (names.length * 2);
+ _BatchNextEnum(batchname, Clone(names), callback, tag, {}, continueOnError, pri); _up();
+ }
+
+ // Request each enum in the batch, stopping if something does not return status 200
+ function _BatchNextEnum(batchname, names, callback, tag, results, continueOnError, pri) {
+ obj.PendingBatchOperations -= 2;
+ var n = names.shift(), f = obj.Enum;
+ if (n[0] == '*') { f = obj.Get; n = n.substring(1); } // If the name starts with a star, do a GET instead of an ENUM. This will reduce round trips.
+ //console.log((f == obj.Get?'Get ':'Enum ') + n);
+ // Perform a GET/ENUM action
+ f(n, function (stack, name, responses, status, tag0) {
+ tag0[2][name] = { response: (responses==null?null:responses.Body), responses: responses, status: status };
+ if (tag0[1].length == 0 || status == 401 || (continueOnError != true && status != 200 && status != 400)) { obj.PendingBatchOperations -= (names.length * 2); _up(); callback(obj, batchname, tag0[2], status, tag); }
+ else { _up(); _BatchNextEnum(batchname, names, callback, tag, tag0[2], pri); }
+ }, [batchname, names, results], pri);
+ _up();
+ }
+
+ // Perform a batch of WSMAN "GET" operations.
+ obj.BatchGet = function (batchname, names, callback, tag, pri) {
+ _FetchNext({ name: batchname, names: names, callback: callback, current: 0, responses: {}, tag: tag, pri: pri }); _up();
+ }
+
+ // Private method
+ function _FetchNext(batch) {
+ if (batch.names.length <= batch.current) {
+ batch.callback(obj, batch.name, batch.responses, 200, batch.tag);
+ } else {
+ obj.wsman.ExecGet(obj.CompleteName(batch.names[batch.current]), function (ws, resuri, response, xstatus) { _Fetched(batch, response, xstatus); }, batch.pri);
+ batch.current++;
+ }
+ _up();
+ }
+
+ // Private method
+ function _Fetched(batch, response, status) {
+ if (response == null || status != 200) {
+ batch.callback(obj, batch.name, null, status, batch.tag);
+ } else {
+ batch.responses[response.Header["Method"]] = response;
+ _FetchNext(batch);
+ }
+ }
+
+ // Private method
+ obj.CompleteName = function(name) {
+ if (name.indexOf("AMT_") == 0) return obj.pfx[0] + name;
+ if (name.indexOf("CIM_") == 0) return obj.pfx[1] + name;
+ if (name.indexOf("IPS_") == 0) return obj.pfx[2] + name;
+ }
+
+ obj.CompleteExecResponse = function (resp) {
+ if (resp && resp != null && resp.Body && (resp.Body["ReturnValue"] != undefined)) { resp.Body.ReturnValueStr = obj.AmtStatusToStr(resp.Body["ReturnValue"]); }
+ return resp;
+ }
+
+ obj.RequestPowerStateChange = function (PowerState, callback_func) {
+ obj.CIM_PowerManagementService_RequestPowerStateChange(PowerState, "http://schemas.xmlsoap.org/ws/2004/08/addressinghttp://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ComputerSystemCIM_ComputerSystemManagedSystem", null, null, callback_func);
+ }
+
+ obj.RequestOSPowerStateChange = function (PowerState, callback_func) {
+ obj.IPS_PowerManagementService_RequestOSPowerSavingStateChange(PowerState, "http://schemas.xmlsoap.org/ws/2004/08/addressinghttp://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ComputerSystemCIM_ComputerSystemManagedSystem", null, null, callback_func);
+ }
+
+ obj.SetBootConfigRole = function (Role, callback_func) {
+ obj.CIM_BootService_SetBootConfigRole("http://schemas.xmlsoap.org/ws/2004/08/addressinghttp://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_BootConfigSettingIntel(r) AMT: Boot Configuration 0", Role, callback_func);
+ }
+
+ // Cancel all pending queries with given status
+ obj.CancelAllQueries = function (s) {
+ obj.wsman.CancelAllQueries(s);
+ }
+
+ // Auto generated methods
+ obj.AMT_AgentPresenceWatchdog_RegisterAgent = function (callback_func) { obj.Exec("AMT_AgentPresenceWatchdog", "RegisterAgent", {}, callback_func); }
+ obj.AMT_AgentPresenceWatchdog_AssertPresence = function (SequenceNumber, callback_func) { obj.Exec("AMT_AgentPresenceWatchdog", "AssertPresence", { "SequenceNumber": SequenceNumber }, callback_func); }
+ obj.AMT_AgentPresenceWatchdog_AssertShutdown = function (SequenceNumber, callback_func) { obj.Exec("AMT_AgentPresenceWatchdog", "AssertShutdown", { "SequenceNumber": SequenceNumber }, callback_func); }
+ obj.AMT_AgentPresenceWatchdog_AddAction = function (OldState, NewState, EventOnTransition, ActionSd, ActionEac, callback_func, tag, pri, selectors) { obj.Exec("AMT_AgentPresenceWatchdog", "AddAction", { "OldState": OldState, "NewState": NewState, "EventOnTransition": EventOnTransition, "ActionSd": ActionSd, "ActionEac": ActionEac }, callback_func, tag, pri, selectors); }
+ obj.AMT_AgentPresenceWatchdog_DeleteAllActions = function (callback_func, tag, pri, selectors) { obj.Exec("AMT_AgentPresenceWatchdog", "DeleteAllActions", {}, callback_func, tag, pri, selectors); }
+ obj.AMT_AgentPresenceWatchdogAction_GetActionEac = function (callback_func) { obj.Exec("AMT_AgentPresenceWatchdogAction", "GetActionEac", {}, callback_func); }
+ obj.AMT_AgentPresenceWatchdogVA_RegisterAgent = function (callback_func) { obj.Exec("AMT_AgentPresenceWatchdogVA", "RegisterAgent", {}, callback_func); }
+ obj.AMT_AgentPresenceWatchdogVA_AssertPresence = function (SequenceNumber, callback_func) { obj.Exec("AMT_AgentPresenceWatchdogVA", "AssertPresence", { "SequenceNumber": SequenceNumber }, callback_func); }
+ obj.AMT_AgentPresenceWatchdogVA_AssertShutdown = function (SequenceNumber, callback_func) { obj.Exec("AMT_AgentPresenceWatchdogVA", "AssertShutdown", { "SequenceNumber": SequenceNumber }, callback_func); }
+ obj.AMT_AgentPresenceWatchdogVA_AddAction = function (OldState, NewState, EventOnTransition, ActionSd, ActionEac, callback_func) { obj.Exec("AMT_AgentPresenceWatchdogVA", "AddAction", { "OldState": OldState, "NewState": NewState, "EventOnTransition": EventOnTransition, "ActionSd": ActionSd, "ActionEac": ActionEac }, callback_func); }
+ obj.AMT_AgentPresenceWatchdogVA_DeleteAllActions = function (_method_dummy, callback_func) { obj.Exec("AMT_AgentPresenceWatchdogVA", "DeleteAllActions", { "_method_dummy": _method_dummy }, callback_func); }
+ obj.AMT_AuditLog_ClearLog = function (callback_func) { obj.Exec("AMT_AuditLog", "ClearLog", {}, callback_func); }
+ obj.AMT_AuditLog_RequestStateChange = function (RequestedState, TimeoutPeriod, callback_func) { obj.Exec("AMT_AuditLog", "RequestStateChange", { "RequestedState": RequestedState, "TimeoutPeriod": TimeoutPeriod }, callback_func); }
+ obj.AMT_AuditLog_ReadRecords = function (StartIndex, callback_func, tag) { obj.Exec("AMT_AuditLog", "ReadRecords", { "StartIndex": StartIndex }, callback_func, tag); }
+ obj.AMT_AuditLog_SetAuditLock = function (LockTimeoutInSeconds, Flag, Handle, callback_func) { obj.Exec("AMT_AuditLog", "SetAuditLock", { "LockTimeoutInSeconds": LockTimeoutInSeconds, "Flag": Flag, "Handle": Handle }, callback_func); }
+ obj.AMT_AuditLog_ExportAuditLogSignature = function (SigningMechanism, callback_func) { obj.Exec("AMT_AuditLog", "ExportAuditLogSignature", { "SigningMechanism": SigningMechanism }, callback_func); }
+ obj.AMT_AuditLog_SetSigningKeyMaterial = function (SigningMechanismType, SigningKey, LengthOfCertificates, Certificates, callback_func) { obj.Exec("AMT_AuditLog", "SetSigningKeyMaterial", { "SigningMechanismType": SigningMechanismType, "SigningKey": SigningKey, "LengthOfCertificates": LengthOfCertificates, "Certificates": Certificates }, callback_func); }
+ obj.AMT_AuditPolicyRule_SetAuditPolicy = function (Enable, AuditedAppID, EventID, PolicyType, callback_func) { obj.Exec("AMT_AuditPolicyRule", "SetAuditPolicy", { "Enable": Enable, "AuditedAppID": AuditedAppID, "EventID": EventID, "PolicyType": PolicyType }, callback_func); }
+ obj.AMT_AuditPolicyRule_SetAuditPolicyBulk = function (Enable, AuditedAppID, EventID, PolicyType, callback_func) { obj.Exec("AMT_AuditPolicyRule", "SetAuditPolicyBulk", { "Enable": Enable, "AuditedAppID": AuditedAppID, "EventID": EventID, "PolicyType": PolicyType }, callback_func); }
+ obj.AMT_AuthorizationService_AddUserAclEntryEx = function (DigestUsername, DigestPassword, KerberosUserSid, AccessPermission, Realms, callback_func) { obj.Exec("AMT_AuthorizationService", "AddUserAclEntryEx", { "DigestUsername": DigestUsername, "DigestPassword": DigestPassword, "KerberosUserSid": KerberosUserSid, "AccessPermission": AccessPermission, "Realms": Realms }, callback_func); }
+ obj.AMT_AuthorizationService_EnumerateUserAclEntries = function (StartIndex, callback_func) { obj.Exec("AMT_AuthorizationService", "EnumerateUserAclEntries", { "StartIndex": StartIndex }, callback_func); }
+ obj.AMT_AuthorizationService_GetUserAclEntryEx = function (Handle, callback_func, tag) { obj.Exec("AMT_AuthorizationService", "GetUserAclEntryEx", { "Handle": Handle }, callback_func, tag); }
+ obj.AMT_AuthorizationService_UpdateUserAclEntryEx = function (Handle, DigestUsername, DigestPassword, KerberosUserSid, AccessPermission, Realms, callback_func) { obj.Exec("AMT_AuthorizationService", "UpdateUserAclEntryEx", { "Handle": Handle, "DigestUsername": DigestUsername, "DigestPassword": DigestPassword, "KerberosUserSid": KerberosUserSid, "AccessPermission": AccessPermission, "Realms": Realms }, callback_func); }
+ obj.AMT_AuthorizationService_RemoveUserAclEntry = function (Handle, callback_func) { obj.Exec("AMT_AuthorizationService", "RemoveUserAclEntry", { "Handle": Handle }, callback_func); }
+ obj.AMT_AuthorizationService_SetAdminAclEntryEx = function (Username, DigestPassword, callback_func) { obj.Exec("AMT_AuthorizationService", "SetAdminAclEntryEx", { "Username": Username, "DigestPassword": DigestPassword }, callback_func); }
+ obj.AMT_AuthorizationService_GetAdminAclEntry = function (callback_func) { obj.Exec("AMT_AuthorizationService", "GetAdminAclEntry", {}, callback_func); }
+ obj.AMT_AuthorizationService_GetAdminAclEntryStatus = function (callback_func) { obj.Exec("AMT_AuthorizationService", "GetAdminAclEntryStatus", {}, callback_func); }
+ obj.AMT_AuthorizationService_GetAdminNetAclEntryStatus = function (callback_func) { obj.Exec("AMT_AuthorizationService", "GetAdminNetAclEntryStatus", {}, callback_func); }
+ obj.AMT_AuthorizationService_SetAclEnabledState = function (Handle, Enabled, callback_func, tag) { obj.Exec("AMT_AuthorizationService", "SetAclEnabledState", { "Handle": Handle, "Enabled": Enabled }, callback_func, tag); }
+ obj.AMT_AuthorizationService_GetAclEnabledState = function (Handle, callback_func, tag) { obj.Exec("AMT_AuthorizationService", "GetAclEnabledState", { "Handle": Handle }, callback_func, tag); }
+ obj.AMT_EndpointAccessControlService_RequestStateChange = function (RequestedState, TimeoutPeriod, callback_func) { obj.Exec("AMT_EndpointAccessControlService", "RequestStateChange", { "RequestedState": RequestedState, "TimeoutPeriod": TimeoutPeriod }, callback_func); }
+ obj.AMT_EndpointAccessControlService_GetPosture = function (PostureType, callback_func) { obj.Exec("AMT_EndpointAccessControlService", "GetPosture", { "PostureType": PostureType }, callback_func); }
+ obj.AMT_EndpointAccessControlService_GetPostureHash = function (PostureType, callback_func) { obj.Exec("AMT_EndpointAccessControlService", "GetPostureHash", { "PostureType": PostureType }, callback_func); }
+ obj.AMT_EndpointAccessControlService_UpdatePostureState = function (UpdateType, callback_func) { obj.Exec("AMT_EndpointAccessControlService", "UpdatePostureState", { "UpdateType": UpdateType }, callback_func); }
+ obj.AMT_EndpointAccessControlService_GetEacOptions = function (callback_func) { obj.Exec("AMT_EndpointAccessControlService", "GetEacOptions", {}, callback_func); }
+ obj.AMT_EndpointAccessControlService_SetEacOptions = function (EacVendors, PostureHashAlgorithm, callback_func) { obj.Exec("AMT_EndpointAccessControlService", "SetEacOptions", { "EacVendors": EacVendors, "PostureHashAlgorithm": PostureHashAlgorithm }, callback_func); }
+ obj.AMT_EnvironmentDetectionSettingData_SetSystemDefensePolicy = function (Policy, callback_func) { obj.Exec("AMT_EnvironmentDetectionSettingData", "SetSystemDefensePolicy", { "Policy": Policy }, callback_func); }
+ obj.AMT_EnvironmentDetectionSettingData_EnableVpnRouting = function (Enable, callback_func) { obj.Exec("AMT_EnvironmentDetectionSettingData", "EnableVpnRouting", { "Enable": Enable }, callback_func); }
+ obj.AMT_EthernetPortSettings_SetLinkPreference = function (LinkPreference, Timeout, callback_func) { obj.Exec("AMT_EthernetPortSettings", "SetLinkPreference", { "LinkPreference": LinkPreference, "Timeout": Timeout }, callback_func); }
+ obj.AMT_HeuristicPacketFilterStatistics_ResetSelectedStats = function (SelectedStatistics, callback_func) { obj.Exec("AMT_HeuristicPacketFilterStatistics", "ResetSelectedStats", { "SelectedStatistics": SelectedStatistics }, callback_func); }
+ obj.AMT_KerberosSettingData_GetCredentialCacheState = function (callback_func) { obj.Exec("AMT_KerberosSettingData", "GetCredentialCacheState", {}, callback_func); }
+ obj.AMT_KerberosSettingData_SetCredentialCacheState = function (Enable, callback_func) { obj.Exec("AMT_KerberosSettingData", "SetCredentialCacheState", { "Enable": Enable }, callback_func); }
+ obj.AMT_MessageLog_CancelIteration = function (IterationIdentifier, callback_func) { obj.Exec("AMT_MessageLog", "CancelIteration", { "IterationIdentifier": IterationIdentifier }, callback_func); }
+ obj.AMT_MessageLog_RequestStateChange = function (RequestedState, TimeoutPeriod, callback_func) { obj.Exec("AMT_MessageLog", "RequestStateChange", { "RequestedState": RequestedState, "TimeoutPeriod": TimeoutPeriod }, callback_func); }
+ obj.AMT_MessageLog_ClearLog = function (callback_func) { obj.Exec("AMT_MessageLog", "ClearLog", { }, callback_func); }
+ obj.AMT_MessageLog_GetRecords = function (IterationIdentifier, MaxReadRecords, callback_func, tag) { obj.Exec("AMT_MessageLog", "GetRecords", { "IterationIdentifier": IterationIdentifier, "MaxReadRecords": MaxReadRecords }, callback_func, tag); }
+ obj.AMT_MessageLog_GetRecord = function (IterationIdentifier, PositionToNext, callback_func) { obj.Exec("AMT_MessageLog", "GetRecord", { "IterationIdentifier": IterationIdentifier, "PositionToNext": PositionToNext }, callback_func); }
+ obj.AMT_MessageLog_PositionAtRecord = function (IterationIdentifier, MoveAbsolute, RecordNumber, callback_func) { obj.Exec("AMT_MessageLog", "PositionAtRecord", { "IterationIdentifier": IterationIdentifier, "MoveAbsolute": MoveAbsolute, "RecordNumber": RecordNumber }, callback_func); }
+ obj.AMT_MessageLog_PositionToFirstRecord = function (callback_func, tag) { obj.Exec("AMT_MessageLog", "PositionToFirstRecord", {}, callback_func, tag); }
+ obj.AMT_MessageLog_FreezeLog = function (Freeze, callback_func) { obj.Exec("AMT_MessageLog", "FreezeLog", { "Freeze": Freeze }, callback_func); }
+ obj.AMT_PublicKeyManagementService_AddCRL = function (Url, SerialNumbers, callback_func) { obj.Exec("AMT_PublicKeyManagementService", "AddCRL", { "Url": Url, "SerialNumbers": SerialNumbers }, callback_func); }
+ obj.AMT_PublicKeyManagementService_ResetCRLList = function (_method_dummy, callback_func) { obj.Exec("AMT_PublicKeyManagementService", "ResetCRLList", { "_method_dummy": _method_dummy }, callback_func); }
+ obj.AMT_PublicKeyManagementService_AddCertificate = function (CertificateBlob, callback_func) { obj.Exec("AMT_PublicKeyManagementService", "AddCertificate", { "CertificateBlob": CertificateBlob }, callback_func); }
+ obj.AMT_PublicKeyManagementService_AddTrustedRootCertificate = function (CertificateBlob, callback_func) { obj.Exec("AMT_PublicKeyManagementService", "AddTrustedRootCertificate", { "CertificateBlob": CertificateBlob }, callback_func); }
+ obj.AMT_PublicKeyManagementService_AddKey = function (KeyBlob, callback_func) { obj.Exec("AMT_PublicKeyManagementService", "AddKey", { "KeyBlob": KeyBlob }, callback_func); }
+ obj.AMT_PublicKeyManagementService_GeneratePKCS10Request = function (KeyPair, DNName, Usage, callback_func) { obj.Exec("AMT_PublicKeyManagementService", "GeneratePKCS10Request", { "KeyPair": KeyPair, "DNName": DNName, "Usage": Usage }, callback_func); }
+ obj.AMT_PublicKeyManagementService_GeneratePKCS10RequestEx = function (KeyPair, SigningAlgorithm, NullSignedCertificateRequest, callback_func) { obj.Exec("AMT_PublicKeyManagementService", "GeneratePKCS10RequestEx", { "KeyPair": KeyPair, "SigningAlgorithm": SigningAlgorithm, "NullSignedCertificateRequest": NullSignedCertificateRequest }, callback_func); }
+ obj.AMT_PublicKeyManagementService_GenerateKeyPair = function (KeyAlgorithm, KeyLength, callback_func) { obj.Exec("AMT_PublicKeyManagementService", "GenerateKeyPair", { "KeyAlgorithm": KeyAlgorithm, "KeyLength": KeyLength }, callback_func); }
+ obj.AMT_RedirectionService_RequestStateChange = function (RequestedState, callback_func) { obj.Exec("AMT_RedirectionService", "RequestStateChange", { "RequestedState": RequestedState }, callback_func); }
+ obj.AMT_RedirectionService_TerminateSession = function (SessionType, callback_func) { obj.Exec("AMT_RedirectionService", "TerminateSession", { "SessionType": SessionType }, callback_func); }
+ obj.AMT_RemoteAccessService_AddMpServer = function (AccessInfo, InfoFormat, Port, AuthMethod, Certificate, Username, Password, CN, callback_func) { obj.Exec("AMT_RemoteAccessService", "AddMpServer", { "AccessInfo": AccessInfo, "InfoFormat": InfoFormat, "Port": Port, "AuthMethod": AuthMethod, "Certificate": Certificate, "Username": Username, "Password": Password, "CN": CN }, callback_func); }
+ obj.AMT_RemoteAccessService_AddRemoteAccessPolicyRule = function (Trigger, TunnelLifeTime, ExtendedData, MpServer, InternalMpServer, callback_func) { obj.Exec("AMT_RemoteAccessService", "AddRemoteAccessPolicyRule", { "Trigger": Trigger, "TunnelLifeTime": TunnelLifeTime, "ExtendedData": ExtendedData, "MpServer": MpServer, "InternalMpServer": InternalMpServer }, callback_func); }
+ obj.AMT_RemoteAccessService_CloseRemoteAccessConnection = function (_method_dummy, callback_func) { obj.Exec("AMT_RemoteAccessService", "CloseRemoteAccessConnection", { "_method_dummy": _method_dummy }, callback_func); }
+ obj.AMT_SetupAndConfigurationService_CommitChanges = function (_method_dummy, callback_func) { obj.Exec("AMT_SetupAndConfigurationService", "CommitChanges", { "_method_dummy": _method_dummy }, callback_func); }
+ obj.AMT_SetupAndConfigurationService_Unprovision = function (ProvisioningMode, callback_func) { obj.Exec("AMT_SetupAndConfigurationService", "Unprovision", { "ProvisioningMode": ProvisioningMode }, callback_func); }
+ obj.AMT_SetupAndConfigurationService_PartialUnprovision = function (_method_dummy, callback_func) { obj.Exec("AMT_SetupAndConfigurationService", "PartialUnprovision", { "_method_dummy": _method_dummy }, callback_func); }
+ obj.AMT_SetupAndConfigurationService_ResetFlashWearOutProtection = function (_method_dummy, callback_func) { obj.Exec("AMT_SetupAndConfigurationService", "ResetFlashWearOutProtection", { "_method_dummy": _method_dummy }, callback_func); }
+ obj.AMT_SetupAndConfigurationService_ExtendProvisioningPeriod = function (Duration, callback_func) { obj.Exec("AMT_SetupAndConfigurationService", "ExtendProvisioningPeriod", { "Duration": Duration }, callback_func); }
+ obj.AMT_SetupAndConfigurationService_SetMEBxPassword = function (Password, callback_func) { obj.Exec("AMT_SetupAndConfigurationService", "SetMEBxPassword", { "Password": Password }, callback_func); }
+ obj.AMT_SetupAndConfigurationService_SetTLSPSK = function (PID, PPS, callback_func) { obj.Exec("AMT_SetupAndConfigurationService", "SetTLSPSK", { "PID": PID, "PPS": PPS }, callback_func); }
+ obj.AMT_SetupAndConfigurationService_GetProvisioningAuditRecord = function (callback_func) { obj.Exec("AMT_SetupAndConfigurationService", "GetProvisioningAuditRecord", {}, callback_func); }
+ obj.AMT_SetupAndConfigurationService_GetUuid = function (callback_func) { obj.Exec("AMT_SetupAndConfigurationService", "GetUuid", {}, callback_func); }
+ obj.AMT_SetupAndConfigurationService_GetUnprovisionBlockingComponents = function (callback_func) { obj.Exec("AMT_SetupAndConfigurationService", "GetUnprovisionBlockingComponents", {}, callback_func); }
+ obj.AMT_SetupAndConfigurationService_GetProvisioningAuditRecordV2 = function (callback_func) { obj.Exec("AMT_SetupAndConfigurationService", "GetProvisioningAuditRecordV2", {}, callback_func); }
+ obj.AMT_SystemDefensePolicy_GetTimeout = function (callback_func) { obj.Exec("AMT_SystemDefensePolicy", "GetTimeout", {}, callback_func); }
+ obj.AMT_SystemDefensePolicy_SetTimeout = function (Timeout, callback_func) { obj.Exec("AMT_SystemDefensePolicy", "SetTimeout", { "Timeout": Timeout }, callback_func); }
+ obj.AMT_SystemDefensePolicy_UpdateStatistics = function (NetworkInterface, ResetOnRead, callback_func, tag, pri, selectors) { obj.Exec("AMT_SystemDefensePolicy", "UpdateStatistics", { "NetworkInterface": NetworkInterface, "ResetOnRead": ResetOnRead }, callback_func, tag, pri, selectors); }
+ obj.AMT_SystemPowerScheme_SetPowerScheme = function (callback_func, schemeInstanceId, tag) { obj.Exec("AMT_SystemPowerScheme", "SetPowerScheme", {}, callback_func, tag, 0, { "InstanceID": schemeInstanceId }); }
+ obj.AMT_TimeSynchronizationService_GetLowAccuracyTimeSynch = function (callback_func, tag) { obj.Exec("AMT_TimeSynchronizationService", "GetLowAccuracyTimeSynch", {}, callback_func, tag); }
+ obj.AMT_TimeSynchronizationService_SetHighAccuracyTimeSynch = function (Ta0, Tm1, Tm2, callback_func, tag) { obj.Exec("AMT_TimeSynchronizationService", "SetHighAccuracyTimeSynch", { "Ta0": Ta0, "Tm1": Tm1, "Tm2": Tm2 }, callback_func, tag); }
+ obj.AMT_UserInitiatedConnectionService_RequestStateChange = function (RequestedState, TimeoutPeriod, callback_func) { obj.Exec("AMT_UserInitiatedConnectionService", "RequestStateChange", { "RequestedState": RequestedState, "TimeoutPeriod": TimeoutPeriod }, callback_func); }
+ obj.AMT_WebUIService_RequestStateChange = function (RequestedState, TimeoutPeriod, callback_func) { obj.Exec("AMT_WebUIService", "RequestStateChange", { "RequestedState": RequestedState, "TimeoutPeriod": TimeoutPeriod }, callback_func); }
+ obj.AMT_WiFiPortConfigurationService_AddWiFiSettings = function (WiFiEndpoint, WiFiEndpointSettingsInput, IEEE8021xSettingsInput, ClientCredential, CACredential, callback_func) { obj.ExecWithXml("AMT_WiFiPortConfigurationService", "AddWiFiSettings", { "WiFiEndpoint": WiFiEndpoint, "WiFiEndpointSettingsInput": WiFiEndpointSettingsInput, "IEEE8021xSettingsInput": IEEE8021xSettingsInput, "ClientCredential": ClientCredential, "CACredential": CACredential }, callback_func); }
+ obj.AMT_WiFiPortConfigurationService_UpdateWiFiSettings = function (WiFiEndpointSettings, WiFiEndpointSettingsInput, IEEE8021xSettingsInput, ClientCredential, CACredential, callback_func) { obj.ExecWithXml("AMT_WiFiPortConfigurationService", "UpdateWiFiSettings", { "WiFiEndpointSettings": WiFiEndpointSettings, "WiFiEndpointSettingsInput": WiFiEndpointSettingsInput, "IEEE8021xSettingsInput": IEEE8021xSettingsInput, "ClientCredential": ClientCredential, "CACredential": CACredential }, callback_func); }
+ obj.AMT_WiFiPortConfigurationService_DeleteAllITProfiles = function (_method_dummy, callback_func) { obj.Exec("AMT_WiFiPortConfigurationService", "DeleteAllITProfiles", { "_method_dummy": _method_dummy }, callback_func); }
+ obj.AMT_WiFiPortConfigurationService_DeleteAllUserProfiles = function (_method_dummy, callback_func) { obj.Exec("AMT_WiFiPortConfigurationService", "DeleteAllUserProfiles", { "_method_dummy": _method_dummy }, callback_func); }
+ obj.CIM_Account_RequestStateChange = function (RequestedState, TimeoutPeriod, callback_func) { obj.Exec("CIM_Account", "RequestStateChange", { "RequestedState": RequestedState, "TimeoutPeriod": TimeoutPeriod }, callback_func); }
+ obj.CIM_AccountManagementService_CreateAccount = function (System, AccountTemplate, callback_func) { obj.Exec("CIM_AccountManagementService", "CreateAccount", { "System": System, "AccountTemplate": AccountTemplate }, callback_func); }
+ obj.CIM_BootConfigSetting_ChangeBootOrder = function (Source, callback_func) { obj.Exec("CIM_BootConfigSetting", "ChangeBootOrder", { "Source": Source }, callback_func); }
+ obj.CIM_BootService_SetBootConfigRole = function (BootConfigSetting, Role, callback_func) { obj.Exec("CIM_BootService", "SetBootConfigRole", { "BootConfigSetting": BootConfigSetting, "Role": Role }, callback_func, 0, 1); }
+ obj.CIM_Card_ConnectorPower = function (Connector, PoweredOn, callback_func) { obj.Exec("CIM_Card", "ConnectorPower", { "Connector": Connector, "PoweredOn": PoweredOn }, callback_func); }
+ obj.CIM_Card_IsCompatible = function (ElementToCheck, callback_func) { obj.Exec("CIM_Card", "IsCompatible", { "ElementToCheck": ElementToCheck }, callback_func); }
+ obj.CIM_Chassis_IsCompatible = function (ElementToCheck, callback_func) { obj.Exec("CIM_Chassis", "IsCompatible", { "ElementToCheck": ElementToCheck }, callback_func); }
+ obj.CIM_Fan_SetSpeed = function (DesiredSpeed, callback_func) { obj.Exec("CIM_Fan", "SetSpeed", { "DesiredSpeed": DesiredSpeed }, callback_func); }
+ obj.CIM_KVMRedirectionSAP_RequestStateChange = function (RequestedState, TimeoutPeriod, callback_func) { obj.Exec("CIM_KVMRedirectionSAP", "RequestStateChange", { "RequestedState": RequestedState/*, "TimeoutPeriod": TimeoutPeriod */}, callback_func); }
+ obj.CIM_MediaAccessDevice_LockMedia = function (Lock, callback_func) { obj.Exec("CIM_MediaAccessDevice", "LockMedia", { "Lock": Lock }, callback_func); }
+ obj.CIM_MediaAccessDevice_SetPowerState = function (PowerState, Time, callback_func) { obj.Exec("CIM_MediaAccessDevice", "SetPowerState", { "PowerState": PowerState, "Time": Time }, callback_func); }
+ obj.CIM_MediaAccessDevice_Reset = function (callback_func) { obj.Exec("CIM_MediaAccessDevice", "Reset", {}, callback_func); }
+ obj.CIM_MediaAccessDevice_EnableDevice = function (Enabled, callback_func) { obj.Exec("CIM_MediaAccessDevice", "EnableDevice", { "Enabled": Enabled }, callback_func); }
+ obj.CIM_MediaAccessDevice_OnlineDevice = function (Online, callback_func) { obj.Exec("CIM_MediaAccessDevice", "OnlineDevice", { "Online": Online }, callback_func); }
+ obj.CIM_MediaAccessDevice_QuiesceDevice = function (Quiesce, callback_func) { obj.Exec("CIM_MediaAccessDevice", "QuiesceDevice", { "Quiesce": Quiesce }, callback_func); }
+ obj.CIM_MediaAccessDevice_SaveProperties = function (callback_func) { obj.Exec("CIM_MediaAccessDevice", "SaveProperties", {}, callback_func); }
+ obj.CIM_MediaAccessDevice_RestoreProperties = function (callback_func) { obj.Exec("CIM_MediaAccessDevice", "RestoreProperties", {}, callback_func); }
+ obj.CIM_MediaAccessDevice_RequestStateChange = function (RequestedState, TimeoutPeriod, callback_func) { obj.Exec("CIM_MediaAccessDevice", "RequestStateChange", { "RequestedState": RequestedState, "TimeoutPeriod": TimeoutPeriod }, callback_func); }
+ obj.CIM_PhysicalFrame_IsCompatible = function (ElementToCheck, callback_func) { obj.Exec("CIM_PhysicalFrame", "IsCompatible", { "ElementToCheck": ElementToCheck }, callback_func); }
+ obj.CIM_PhysicalPackage_IsCompatible = function (ElementToCheck, callback_func) { obj.Exec("CIM_PhysicalPackage", "IsCompatible", { "ElementToCheck": ElementToCheck }, callback_func); }
+ obj.CIM_PowerManagementService_RequestPowerStateChange = function (PowerState, ManagedElement, Time, TimeoutPeriod, callback_func) { obj.Exec("CIM_PowerManagementService", "RequestPowerStateChange", { "PowerState": PowerState, "ManagedElement": ManagedElement, "Time": Time, "TimeoutPeriod": TimeoutPeriod }, callback_func, 0, 1); }
+ obj.CIM_PowerSupply_SetPowerState = function (PowerState, Time, callback_func) { obj.Exec("CIM_PowerSupply", "SetPowerState", { "PowerState": PowerState, "Time": Time }, callback_func); }
+ obj.CIM_PowerSupply_Reset = function (callback_func) { obj.Exec("CIM_PowerSupply", "Reset", {}, callback_func); }
+ obj.CIM_PowerSupply_EnableDevice = function (Enabled, callback_func) { obj.Exec("CIM_PowerSupply", "EnableDevice", { "Enabled": Enabled }, callback_func); }
+ obj.CIM_PowerSupply_OnlineDevice = function (Online, callback_func) { obj.Exec("CIM_PowerSupply", "OnlineDevice", { "Online": Online }, callback_func); }
+ obj.CIM_PowerSupply_QuiesceDevice = function (Quiesce, callback_func) { obj.Exec("CIM_PowerSupply", "QuiesceDevice", { "Quiesce": Quiesce }, callback_func); }
+ obj.CIM_PowerSupply_SaveProperties = function (callback_func) { obj.Exec("CIM_PowerSupply", "SaveProperties", {}, callback_func); }
+ obj.CIM_PowerSupply_RestoreProperties = function (callback_func) { obj.Exec("CIM_PowerSupply", "RestoreProperties", {}, callback_func); }
+ obj.CIM_PowerSupply_RequestStateChange = function (RequestedState, TimeoutPeriod, callback_func) { obj.Exec("CIM_PowerSupply", "RequestStateChange", { "RequestedState": RequestedState, "TimeoutPeriod": TimeoutPeriod }, callback_func); }
+ obj.CIM_Processor_SetPowerState = function (PowerState, Time, callback_func) { obj.Exec("CIM_Processor", "SetPowerState", { "PowerState": PowerState, "Time": Time }, callback_func); }
+ obj.CIM_Processor_Reset = function (callback_func) { obj.Exec("CIM_Processor", "Reset", {}, callback_func); }
+ obj.CIM_Processor_EnableDevice = function (Enabled, callback_func) { obj.Exec("CIM_Processor", "EnableDevice", { "Enabled": Enabled }, callback_func); }
+ obj.CIM_Processor_OnlineDevice = function (Online, callback_func) { obj.Exec("CIM_Processor", "OnlineDevice", { "Online": Online }, callback_func); }
+ obj.CIM_Processor_QuiesceDevice = function (Quiesce, callback_func) { obj.Exec("CIM_Processor", "QuiesceDevice", { "Quiesce": Quiesce }, callback_func); }
+ obj.CIM_Processor_SaveProperties = function (callback_func) { obj.Exec("CIM_Processor", "SaveProperties", {}, callback_func); }
+ obj.CIM_Processor_RestoreProperties = function (callback_func) { obj.Exec("CIM_Processor", "RestoreProperties", {}, callback_func); }
+ obj.CIM_Processor_RequestStateChange = function (RequestedState, TimeoutPeriod, callback_func) { obj.Exec("CIM_Processor", "RequestStateChange", { "RequestedState": RequestedState, "TimeoutPeriod": TimeoutPeriod }, callback_func); }
+ obj.CIM_RecordLog_ClearLog = function (callback_func) { obj.Exec("CIM_RecordLog", "ClearLog", {}, callback_func); }
+ obj.CIM_RecordLog_RequestStateChange = function (RequestedState, TimeoutPeriod, callback_func) { obj.Exec("CIM_RecordLog", "RequestStateChange", { "RequestedState": RequestedState, "TimeoutPeriod": TimeoutPeriod }, callback_func); }
+ obj.CIM_RedirectionService_RequestStateChange = function (RequestedState, TimeoutPeriod, callback_func) { obj.Exec("CIM_RedirectionService", "RequestStateChange", { "RequestedState": RequestedState, "TimeoutPeriod": TimeoutPeriod }, callback_func); }
+ obj.CIM_Sensor_SetPowerState = function (PowerState, Time, callback_func) { obj.Exec("CIM_Sensor", "SetPowerState", { "PowerState": PowerState, "Time": Time }, callback_func); }
+ obj.CIM_Sensor_Reset = function (callback_func) { obj.Exec("CIM_Sensor", "Reset", {}, callback_func); }
+ obj.CIM_Sensor_EnableDevice = function (Enabled, callback_func) { obj.Exec("CIM_Sensor", "EnableDevice", { "Enabled": Enabled }, callback_func); }
+ obj.CIM_Sensor_OnlineDevice = function (Online, callback_func) { obj.Exec("CIM_Sensor", "OnlineDevice", { "Online": Online }, callback_func); }
+ obj.CIM_Sensor_QuiesceDevice = function (Quiesce, callback_func) { obj.Exec("CIM_Sensor", "QuiesceDevice", { "Quiesce": Quiesce }, callback_func); }
+ obj.CIM_Sensor_SaveProperties = function (callback_func) { obj.Exec("CIM_Sensor", "SaveProperties", {}, callback_func); }
+ obj.CIM_Sensor_RestoreProperties = function (callback_func) { obj.Exec("CIM_Sensor", "RestoreProperties", {}, callback_func); }
+ obj.CIM_Sensor_RequestStateChange = function (RequestedState, TimeoutPeriod, callback_func) { obj.Exec("CIM_Sensor", "RequestStateChange", { "RequestedState": RequestedState, "TimeoutPeriod": TimeoutPeriod }, callback_func); }
+ obj.CIM_StatisticalData_ResetSelectedStats = function (SelectedStatistics, callback_func) { obj.Exec("CIM_StatisticalData", "ResetSelectedStats", { "SelectedStatistics": SelectedStatistics }, callback_func); }
+ obj.CIM_Watchdog_KeepAlive = function (callback_func) { obj.Exec("CIM_Watchdog", "KeepAlive", {}, callback_func); }
+ obj.CIM_Watchdog_SetPowerState = function (PowerState, Time, callback_func) { obj.Exec("CIM_Watchdog", "SetPowerState", { "PowerState": PowerState, "Time": Time }, callback_func); }
+ obj.CIM_Watchdog_Reset = function (callback_func) { obj.Exec("CIM_Watchdog", "Reset", {}, callback_func); }
+ obj.CIM_Watchdog_EnableDevice = function (Enabled, callback_func) { obj.Exec("CIM_Watchdog", "EnableDevice", { "Enabled": Enabled }, callback_func); }
+ obj.CIM_Watchdog_OnlineDevice = function (Online, callback_func) { obj.Exec("CIM_Watchdog", "OnlineDevice", { "Online": Online }, callback_func); }
+ obj.CIM_Watchdog_QuiesceDevice = function (Quiesce, callback_func) { obj.Exec("CIM_Watchdog", "QuiesceDevice", { "Quiesce": Quiesce }, callback_func); }
+ obj.CIM_Watchdog_SaveProperties = function (callback_func) { obj.Exec("CIM_Watchdog", "SaveProperties", {}, callback_func); }
+ obj.CIM_Watchdog_RestoreProperties = function (callback_func) { obj.Exec("CIM_Watchdog", "RestoreProperties", {}, callback_func); }
+ obj.CIM_Watchdog_RequestStateChange = function (RequestedState, TimeoutPeriod, callback_func) { obj.Exec("CIM_Watchdog", "RequestStateChange", { "RequestedState": RequestedState, "TimeoutPeriod": TimeoutPeriod }, callback_func); }
+ obj.CIM_WiFiPort_SetPowerState = function (PowerState, Time, callback_func) { obj.Exec("CIM_WiFiPort", "SetPowerState", { "PowerState": PowerState, "Time": Time }, callback_func); }
+ obj.CIM_WiFiPort_Reset = function (callback_func) { obj.Exec("CIM_WiFiPort", "Reset", {}, callback_func); }
+ obj.CIM_WiFiPort_EnableDevice = function (Enabled, callback_func) { obj.Exec("CIM_WiFiPort", "EnableDevice", { "Enabled": Enabled }, callback_func); }
+ obj.CIM_WiFiPort_OnlineDevice = function (Online, callback_func) { obj.Exec("CIM_WiFiPort", "OnlineDevice", { "Online": Online }, callback_func); }
+ obj.CIM_WiFiPort_QuiesceDevice = function (Quiesce, callback_func) { obj.Exec("CIM_WiFiPort", "QuiesceDevice", { "Quiesce": Quiesce }, callback_func); }
+ obj.CIM_WiFiPort_SaveProperties = function (callback_func) { obj.Exec("CIM_WiFiPort", "SaveProperties", {}, callback_func); }
+ obj.CIM_WiFiPort_RestoreProperties = function (callback_func) { obj.Exec("CIM_WiFiPort", "RestoreProperties", {}, callback_func); }
+ obj.CIM_WiFiPort_RequestStateChange = function (RequestedState, TimeoutPeriod, callback_func) { obj.Exec("CIM_WiFiPort", "RequestStateChange", { "RequestedState": RequestedState, "TimeoutPeriod": TimeoutPeriod }, callback_func); }
+ obj.IPS_HostBasedSetupService_Setup = function (NetAdminPassEncryptionType, NetworkAdminPassword, McNonce, Certificate, SigningAlgorithm, DigitalSignature, callback_func) { obj.Exec("IPS_HostBasedSetupService", "Setup", { "NetAdminPassEncryptionType": NetAdminPassEncryptionType, "NetworkAdminPassword": NetworkAdminPassword, "McNonce": McNonce, "Certificate": Certificate, "SigningAlgorithm": SigningAlgorithm, "DigitalSignature": DigitalSignature }, callback_func); }
+ obj.IPS_HostBasedSetupService_AddNextCertInChain = function (NextCertificate, IsLeafCertificate, IsRootCertificate, callback_func) { obj.Exec("IPS_HostBasedSetupService", "AddNextCertInChain", { "NextCertificate": NextCertificate, "IsLeafCertificate": IsLeafCertificate, "IsRootCertificate": IsRootCertificate }, callback_func); }
+ obj.IPS_HostBasedSetupService_AdminSetup = function (NetAdminPassEncryptionType, NetworkAdminPassword, McNonce, SigningAlgorithm, DigitalSignature, callback_func) { obj.Exec("IPS_HostBasedSetupService", "AdminSetup", { "NetAdminPassEncryptionType": NetAdminPassEncryptionType, "NetworkAdminPassword": NetworkAdminPassword, "McNonce": McNonce, "SigningAlgorithm": SigningAlgorithm, "DigitalSignature": DigitalSignature }, callback_func); }
+ obj.IPS_HostBasedSetupService_UpgradeClientToAdmin = function (McNonce, SigningAlgorithm, DigitalSignature, callback_func) { obj.Exec("IPS_HostBasedSetupService", "UpgradeClientToAdmin", { "McNonce": McNonce, "SigningAlgorithm": SigningAlgorithm, "DigitalSignature": DigitalSignature }, callback_func); }
+ obj.IPS_HostBasedSetupService_DisableClientControlMode = function (_method_dummy, callback_func) { obj.Exec("IPS_HostBasedSetupService", "DisableClientControlMode", { "_method_dummy": _method_dummy }, callback_func); }
+ obj.IPS_KVMRedirectionSettingData_TerminateSession = function (callback_func) { obj.Exec("IPS_KVMRedirectionSettingData", "TerminateSession", {}, callback_func); }
+ obj.IPS_KVMRedirectionSettingData_DataChannelRead = function (callback_func) { obj.Exec("IPS_KVMRedirectionSettingData", "DataChannelRead", {}, callback_func); }
+ obj.IPS_KVMRedirectionSettingData_DataChannelWrite = function (Data, callback_func) { obj.Exec("IPS_KVMRedirectionSettingData", "DataChannelWrite", { "DataMessage": Data }, callback_func); }
+ obj.IPS_OptInService_StartOptIn = function (callback_func) { obj.Exec("IPS_OptInService", "StartOptIn", {}, callback_func); }
+ obj.IPS_OptInService_CancelOptIn = function (callback_func) { obj.Exec("IPS_OptInService", "CancelOptIn", {}, callback_func); }
+ obj.IPS_OptInService_SendOptInCode = function (OptInCode, callback_func) { obj.Exec("IPS_OptInService", "SendOptInCode", { "OptInCode": OptInCode }, callback_func); }
+ obj.IPS_OptInService_StartService = function (callback_func) { obj.Exec("IPS_OptInService", "StartService", {}, callback_func); }
+ obj.IPS_OptInService_StopService = function (callback_func) { obj.Exec("IPS_OptInService", "StopService", {}, callback_func); }
+ obj.IPS_OptInService_RequestStateChange = function (RequestedState, TimeoutPeriod, callback_func) { obj.Exec("IPS_OptInService", "RequestStateChange", { "RequestedState": RequestedState, "TimeoutPeriod": TimeoutPeriod }, callback_func); }
+ obj.IPS_PowerManagementService_RequestOSPowerSavingStateChange = function (PowerState, ManagedElement, Time, TimeoutPeriod, callback_func) { obj.Exec("IPS_PowerManagementService", "RequestOSPowerSavingStateChange", { "OSPowerSavingState": PowerState, "ManagedElement": ManagedElement, "Time": Time, "TimeoutPeriod": TimeoutPeriod }, callback_func, 0, 1); }
+ obj.IPS_ProvisioningRecordLog_RequestStateChange = function (RequestedState, TimeoutPeriod, callback_func) { obj.Exec("IPS_ProvisioningRecordLog", "RequestStateChange", { "RequestedState": RequestedState, "TimeoutPeriod": TimeoutPeriod }, callback_func); }
+ obj.IPS_ProvisioningRecordLog_ClearLog = function (_method_dummy, callback_func) { obj.Exec("IPS_ProvisioningRecordLog", "ClearLog", { "_method_dummy": _method_dummy }, callback_func); }
+ obj.IPS_ScreenConfigurationService_SetSessionState = function (SessionState, ConsecutiveRebootsNum, callback_func) { obj.Exec("IPS_ScreenConfigurationService", "SetSessionState", { "SessionState": SessionState, "ConsecutiveRebootsNum": ConsecutiveRebootsNum }, callback_func); }
+ obj.IPS_SecIOService_RequestStateChange = function (RequestedState, TimeoutPeriod, callback_func) { obj.Exec("IPS_SecIOService", "RequestStateChange", { "RequestedState": RequestedState, "TimeoutPeriod": TimeoutPeriod }, callback_func); }
+ obj.IPS_HTTPProxyService_AddProxyAccessPoint = function (AccessInfo, InfoFormat, Port, NetworkDnsSuffix, callback_func) { obj.Exec("IPS_HTTPProxyService", "AddProxyAccessPoint", { "AccessInfo": AccessInfo, "InfoFormat": InfoFormat, "Port": Port, "NetworkDnsSuffix": NetworkDnsSuffix }, callback_func); }
+
+ obj.AmtStatusToStr = function (code) { if (obj.AmtStatusCodes[code]) return obj.AmtStatusCodes[code]; else return "UNKNOWN_ERROR" }
+ obj.AmtStatusCodes = {
+ 0x0000: "SUCCESS",
+ 0x0001: "INTERNAL_ERROR",
+ 0x0002: "NOT_READY",
+ 0x0003: "INVALID_PT_MODE",
+ 0x0004: "INVALID_MESSAGE_LENGTH",
+ 0x0005: "TABLE_FINGERPRINT_NOT_AVAILABLE",
+ 0x0006: "INTEGRITY_CHECK_FAILED",
+ 0x0007: "UNSUPPORTED_ISVS_VERSION",
+ 0x0008: "APPLICATION_NOT_REGISTERED",
+ 0x0009: "INVALID_REGISTRATION_DATA",
+ 0x000A: "APPLICATION_DOES_NOT_EXIST",
+ 0x000B: "NOT_ENOUGH_STORAGE",
+ 0x000C: "INVALID_NAME",
+ 0x000D: "BLOCK_DOES_NOT_EXIST",
+ 0x000E: "INVALID_BYTE_OFFSET",
+ 0x000F: "INVALID_BYTE_COUNT",
+ 0x0010: "NOT_PERMITTED",
+ 0x0011: "NOT_OWNER",
+ 0x0012: "BLOCK_LOCKED_BY_OTHER",
+ 0x0013: "BLOCK_NOT_LOCKED",
+ 0x0014: "INVALID_GROUP_PERMISSIONS",
+ 0x0015: "GROUP_DOES_NOT_EXIST",
+ 0x0016: "INVALID_MEMBER_COUNT",
+ 0x0017: "MAX_LIMIT_REACHED",
+ 0x0018: "INVALID_AUTH_TYPE",
+ 0x0019: "AUTHENTICATION_FAILED",
+ 0x001A: "INVALID_DHCP_MODE",
+ 0x001B: "INVALID_IP_ADDRESS",
+ 0x001C: "INVALID_DOMAIN_NAME",
+ 0x001D: "UNSUPPORTED_VERSION",
+ 0x001E: "REQUEST_UNEXPECTED",
+ 0x001F: "INVALID_TABLE_TYPE",
+ 0x0020: "INVALID_PROVISIONING_STATE",
+ 0x0021: "UNSUPPORTED_OBJECT",
+ 0x0022: "INVALID_TIME",
+ 0x0023: "INVALID_INDEX",
+ 0x0024: "INVALID_PARAMETER",
+ 0x0025: "INVALID_NETMASK",
+ 0x0026: "FLASH_WRITE_LIMIT_EXCEEDED",
+ 0x0027: "INVALID_IMAGE_LENGTH",
+ 0x0028: "INVALID_IMAGE_SIGNATURE",
+ 0x0029: "PROPOSE_ANOTHER_VERSION",
+ 0x002A: "INVALID_PID_FORMAT",
+ 0x002B: "INVALID_PPS_FORMAT",
+ 0x002C: "BIST_COMMAND_BLOCKED",
+ 0x002D: "CONNECTION_FAILED",
+ 0x002E: "CONNECTION_TOO_MANY",
+ 0x002F: "RNG_GENERATION_IN_PROGRESS",
+ 0x0030: "RNG_NOT_READY",
+ 0x0031: "CERTIFICATE_NOT_READY",
+ 0x0400: "DISABLED_BY_POLICY",
+ 0x0800: "NETWORK_IF_ERROR_BASE",
+ 0x0801: "UNSUPPORTED_OEM_NUMBER",
+ 0x0802: "UNSUPPORTED_BOOT_OPTION",
+ 0x0803: "INVALID_COMMAND",
+ 0x0804: "INVALID_SPECIAL_COMMAND",
+ 0x0805: "INVALID_HANDLE",
+ 0x0806: "INVALID_PASSWORD",
+ 0x0807: "INVALID_REALM",
+ 0x0808: "STORAGE_ACL_ENTRY_IN_USE",
+ 0x0809: "DATA_MISSING",
+ 0x080A: "DUPLICATE",
+ 0x080B: "EVENTLOG_FROZEN",
+ 0x080C: "PKI_MISSING_KEYS",
+ 0x080D: "PKI_GENERATING_KEYS",
+ 0x080E: "INVALID_KEY",
+ 0x080F: "INVALID_CERT",
+ 0x0810: "CERT_KEY_NOT_MATCH",
+ 0x0811: "MAX_KERB_DOMAIN_REACHED",
+ 0x0812: "UNSUPPORTED",
+ 0x0813: "INVALID_PRIORITY",
+ 0x0814: "NOT_FOUND",
+ 0x0815: "INVALID_CREDENTIALS",
+ 0x0816: "INVALID_PASSPHRASE",
+ 0x0818: "NO_ASSOCIATION",
+ 0x081B: "AUDIT_FAIL",
+ 0x081C: "BLOCKING_COMPONENT",
+ 0x0821: "USER_CONSENT_REQUIRED",
+ 0x1000: "APP_INTERNAL_ERROR",
+ 0x1001: "NOT_INITIALIZED",
+ 0x1002: "LIB_VERSION_UNSUPPORTED",
+ 0x1003: "INVALID_PARAM",
+ 0x1004: "RESOURCES",
+ 0x1005: "HARDWARE_ACCESS_ERROR",
+ 0x1006: "REQUESTOR_NOT_REGISTERED",
+ 0x1007: "NETWORK_ERROR",
+ 0x1008: "PARAM_BUFFER_TOO_SHORT",
+ 0x1009: "COM_NOT_INITIALIZED_IN_THREAD",
+ 0x100A: "URL_REQUIRED"
+ }
+
+ //
+ // Methods used for getting the event log
+ //
+
+ obj.GetMessageLog = function (func, tag) {
+ obj.AMT_MessageLog_PositionToFirstRecord(_GetMessageLog0, [func, tag, []]);
+ }
+ function _GetMessageLog0(stack, name, responses, status, tag) {
+ if (status != 200 || responses.Body['ReturnValue'] != '0') { tag[0](obj, null, tag[2]); return; }
+ obj.AMT_MessageLog_GetRecords(responses.Body["IterationIdentifier"], 390, _GetMessageLog1, tag);
+ }
+ function _GetMessageLog1(stack, name, responses, status, tag) {
+ if (status != 200 || responses.Body['ReturnValue'] != '0') { tag[0](obj, null, tag[2]); return; }
+ var i, j, x, e, AmtMessages = tag[2], t = new Date(), TimeStamp, ra = responses.Body['RecordArray'];
+ if (typeof ra === 'string') { responses.Body['RecordArray'] = [responses.Body['RecordArray']]; }
+
+ for (i in ra) {
+ e = null;
+ try {
+ // ###BEGIN###{!Mode-MeshCentral2}
+ // NodeJS detection
+ var isNode = new Function('try {return this===global;}catch(e){return false;}');
+ if (isNode()) { e = require('atob')(ra[i]); } else { e = window.atob(ra[i]); }
+ // ###END###{!Mode-MeshCentral2}
+ // ###BEGIN###{Mode-MeshCentral2}
+ e = window.atob(ra[i]);
+ // ###END###{Mode-MeshCentral2}
+ } catch (ex) { }
+ if (e != null) {
+ TimeStamp = ReadIntX(e, 0);
+ if ((TimeStamp > 0) && (TimeStamp < 0xFFFFFFFF)) {
+ x = { 'DeviceAddress': e.charCodeAt(4), 'EventSensorType': e.charCodeAt(5), 'EventType': e.charCodeAt(6), 'EventOffset': e.charCodeAt(7), 'EventSourceType': e.charCodeAt(8), 'EventSeverity': e.charCodeAt(9), 'SensorNumber': e.charCodeAt(10), 'Entity': e.charCodeAt(11), 'EntityInstance': e.charCodeAt(12), 'EventData': [], 'Time': new Date((TimeStamp + (t.getTimezoneOffset() * 60)) * 1000) };
+ for (j = 13; j < 21; j++) { x['EventData'].push(e.charCodeAt(j)); }
+ x['EntityStr'] = _SystemEntityTypes[x['Entity']];
+ x['Desc'] = _GetEventDetailStr(x['EventSensorType'], x['EventOffset'], x['EventData'], x['Entity']);
+ if (!x['EntityStr']) x['EntityStr'] = "Unknown";
+ AmtMessages.push(x);
+ }
+ }
+ }
+
+ if (responses.Body["NoMoreRecords"] != true) { obj.AMT_MessageLog_GetRecords(responses.Body["IterationIdentifier"], 390, _GetMessageLog1, [tag[0], AmtMessages, tag[2]]); } else { tag[0](obj, AmtMessages, tag[2]); }
+ }
+
+ var _EventTrapSourceTypes = "Platform firmware (e.g. BIOS)|SMI handler|ISV system management software|Alert ASIC|IPMI|BIOS vendor|System board set vendor|System integrator|Third party add-in|OSV|NIC|System management card".split('|');
+ var _SystemFirmwareError = "Unspecified.|No system memory is physically installed in the system.|No usable system memory, all installed memory has experienced an unrecoverable failure.|Unrecoverable hard-disk/ATAPI/IDE device failure.|Unrecoverable system-board failure.|Unrecoverable diskette subsystem failure.|Unrecoverable hard-disk controller failure.|Unrecoverable PS/2 or USB keyboard failure.|Removable boot media not found.|Unrecoverable video controller failure.|No video device detected.|Firmware (BIOS) ROM corruption detected.|CPU voltage mismatch (processors that share same supply have mismatched voltage requirements)|CPU speed matching failure".split('|');
+ var _SystemFirmwareProgress = "Unspecified.|Memory initialization.|Starting hard-disk initialization and test|Secondary processor(s) initialization|User authentication|User-initiated system setup|USB resource configuration|PCI resource configuration|Option ROM initialization|Video initialization|Cache initialization|SM Bus initialization|Keyboard controller initialization|Embedded controller/management controller initialization|Docking station attachment|Enabling docking station|Docking station ejection|Disabling docking station|Calling operating system wake-up vector|Starting operating system boot process|Baseboard or motherboard initialization|reserved|Floppy initialization|Keyboard test|Pointing device test|Primary processor initialization".split('|');
+ var _SystemEntityTypes = "Unspecified|Other|Unknown|Processor|Disk|Peripheral|System management module|System board|Memory module|Processor module|Power supply|Add in card|Front panel board|Back panel board|Power system board|Drive backplane|System internal expansion board|Other system board|Processor board|Power unit|Power module|Power management board|Chassis back panel board|System chassis|Sub chassis|Other chassis board|Disk drive bay|Peripheral bay|Device bay|Fan cooling|Cooling unit|Cable interconnect|Memory device|System management software|BIOS|Intel(r) ME|System bus|Group|Intel(r) ME|External environment|Battery|Processing blade|Connectivity switch|Processor/memory module|I/O module|Processor I/O module|Management controller firmware|IPMI channel|PCI bus|PCI express bus|SCSI bus|SATA/SAS bus|Processor front side bus".split('|');
+ obj.RealmNames = "||Redirection||Hardware Asset|Remote Control|Storage|Event Manager|Storage Admin|Agent Presence Local|Agent Presence Remote|Circuit Breaker|Network Time|General Information|Firmware Update|EIT|LocalUN|Endpoint Access Control|Endpoint Access Control Admin|Event Log Reader|Audit Log|ACL Realm|||Local System".split('|');
+ obj.WatchdogCurrentStates = { 1: 'Not Started', 2: 'Stopped', 4: 'Running', 8: 'Expired', 16: 'Suspended' };
+
+ function _GetEventDetailStr(eventSensorType, eventOffset, eventDataField, entity) {
+
+ if (eventSensorType == 15) {
+ if (eventDataField[0] == 235) return "Invalid Data";
+ if (eventOffset == 0) return _SystemFirmwareError[eventDataField[1]];
+ return _SystemFirmwareProgress[eventDataField[1]];
+ }
+
+ if ((eventSensorType == 18) && (eventDataField[0] == 170)) { // System watchdog event
+ return "Agent watchdog " + char2hex(eventDataField[4]) + char2hex(eventDataField[3]) + char2hex(eventDataField[2]) + char2hex(eventDataField[1]) + "-" + char2hex(eventDataField[6]) + char2hex(eventDataField[5]) + "-... changed to " + obj.WatchdogCurrentStates[eventDataField[7]];
+ }
+
+ if ((eventSensorType == 5) && (eventOffset == 0)) { // System chassis
+ return "Case intrusion";
+ }
+
+ if ((eventSensorType == 192) && (eventOffset == 0) && (eventDataField[0] == 170) && (eventDataField[1] == 48))
+ {
+ if (eventDataField[2] == 0) return "A remote Serial Over LAN session was established.";
+ if (eventDataField[2] == 1) return "Remote Serial Over LAN session finished. User control was restored.";
+ if (eventDataField[2] == 2) return "A remote IDE-Redirection session was established.";
+ if (eventDataField[2] == 3) return "Remote IDE-Redirection session finished. User control was restored.";
+ }
+
+ if (eventSensorType == 36) {
+ var handle = (eventDataField[1] << 24) + (eventDataField[2] << 16) + (eventDataField[3] << 8) + eventDataField[4];
+ var nic = "#" + eventDataField[0];
+ if (eventDataField[0] == 0xAA) nic = "wired"; // TODO: Add wireless *****
+ //if (eventDataField[0] == 0xAA) nic = "wireless";
+
+ if (handle == 4294967293) { return "All received packet filter was matched on " + nic + " interface."; }
+ if (handle == 4294967292) { return "All outbound packet filter was matched on " + nic + " interface."; }
+ if (handle == 4294967290) { return "Spoofed packet filter was matched on " + nic + " interface."; }
+ return "Filter " + handle + " was matched on " + nic + " interface.";
+ }
+
+ if (eventSensorType == 192) {
+ if (eventDataField[2] == 0) return "Security policy invoked. Some or all network traffic (TX) was stopped.";
+ if (eventDataField[2] == 2) return "Security policy invoked. Some or all network traffic (RX) was stopped.";
+ return "Security policy invoked.";
+ }
+
+ if (eventSensorType == 193) {
+ if ((eventDataField[0] == 0xAA) && (eventDataField[1] == 0x30) && (eventDataField[2] == 0x00) && (eventDataField[3] == 0x00)) { return "User request for remote connection."; }
+ if ((eventDataField[0] == 0xAA) && (eventDataField[1] == 0x20) && (eventDataField[2] == 0x03) && (eventDataField[3] == 0x01)) { return "EAC error: attempt to get posture while NAC in Intel® AMT is disabled."; } // eventDataField = 0xAA20030100000000
+ if ((eventDataField[0] == 0xAA) && (eventDataField[1] == 0x20) && (eventDataField[2] == 0x04) && (eventDataField[3] == 0x00)) { return "HWA Error: general error"; } // Used to be "Certificate revoked." but don't know the source of this.
+ }
+
+ if (eventSensorType == 6) return "Authentication failed " + (eventDataField[1] + (eventDataField[2] << 8)) + " times. The system may be under attack.";
+ if (eventSensorType == 30) return "No bootable media";
+ if (eventSensorType == 32) return "Operating system lockup or power interrupt";
+ if (eventSensorType == 35) return "System boot failure";
+ if (eventSensorType == 37) return "System firmware started (at least one CPU is properly executing).";
+ return "Unknown Sensor Type #" + eventSensorType;
+ }
+
+// ###BEGIN###{AuditLog}
+
+ // Useful link: https://software.intel.com/sites/manageability/AMT_Implementation_and_Reference_Guide/default.htm?turl=WordDocuments%2Fsecurityadminevents.htm
+
+ var _AmtAuditStringTable =
+ {
+ 16: 'Security Admin',
+ 17: 'RCO',
+ 18: 'Redirection Manager',
+ 19: 'Firmware Update Manager',
+ 20: 'Security Audit Log',
+ 21: 'Network Time',
+ 22: 'Network Administration',
+ 23: 'Storage Administration',
+ 24: 'Event Manager',
+ 25: 'Circuit Breaker Manager',
+ 26: 'Agent Presence Manager',
+ 27: 'Wireless Configuration',
+ 28: 'EAC',
+ 29: 'KVM',
+ 30: 'User Opt-In Events',
+ 32: 'Screen Blanking',
+ 33: 'Watchdog Events',
+ 1600: 'Provisioning Started',
+ 1601: 'Provisioning Completed',
+ 1602: 'ACL Entry Added',
+ 1603: 'ACL Entry Modified',
+ 1604: 'ACL Entry Removed',
+ 1605: 'ACL Access with Invalid Credentials',
+ 1606: 'ACL Entry State',
+ 1607: 'TLS State Changed',
+ 1608: 'TLS Server Certificate Set',
+ 1609: 'TLS Server Certificate Remove',
+ 1610: 'TLS Trusted Root Certificate Added',
+ 1611: 'TLS Trusted Root Certificate Removed',
+ 1612: 'TLS Preshared Key Set',
+ 1613: 'Kerberos Settings Modified',
+ 1614: 'Kerberos Master Key Modified',
+ 1615: 'Flash Wear out Counters Reset',
+ 1616: 'Power Package Modified',
+ 1617: 'Set Realm Authentication Mode',
+ 1618: 'Upgrade Client to Admin Control Mode',
+ 1619: 'Unprovisioning Started',
+ 1700: 'Performed Power Up',
+ 1701: 'Performed Power Down',
+ 1702: 'Performed Power Cycle',
+ 1703: 'Performed Reset',
+ 1704: 'Set Boot Options',
+ 1800: 'IDER Session Opened',
+ 1801: 'IDER Session Closed',
+ 1802: 'IDER Enabled',
+ 1803: 'IDER Disabled',
+ 1804: 'SoL Session Opened',
+ 1805: 'SoL Session Closed',
+ 1806: 'SoL Enabled',
+ 1807: 'SoL Disabled',
+ 1808: 'KVM Session Started',
+ 1809: 'KVM Session Ended',
+ 1810: 'KVM Enabled',
+ 1811: 'KVM Disabled',
+ 1812: 'VNC Password Failed 3 Times',
+ 1900: 'Firmware Updated',
+ 1901: 'Firmware Update Failed',
+ 2000: 'Security Audit Log Cleared',
+ 2001: 'Security Audit Policy Modified',
+ 2002: 'Security Audit Log Disabled',
+ 2003: 'Security Audit Log Enabled',
+ 2004: 'Security Audit Log Exported',
+ 2005: 'Security Audit Log Recovered',
+ 2100: 'Intel® ME Time Set',
+ 2200: 'TCPIP Parameters Set',
+ 2201: 'Host Name Set',
+ 2202: 'Domain Name Set',
+ 2203: 'VLAN Parameters Set',
+ 2204: 'Link Policy Set',
+ 2205: 'IPv6 Parameters Set',
+ 2300: 'Global Storage Attributes Set',
+ 2301: 'Storage EACL Modified',
+ 2302: 'Storage FPACL Modified',
+ 2303: 'Storage Write Operation',
+ 2400: 'Alert Subscribed',
+ 2401: 'Alert Unsubscribed',
+ 2402: 'Event Log Cleared',
+ 2403: 'Event Log Frozen',
+ 2500: 'CB Filter Added',
+ 2501: 'CB Filter Removed',
+ 2502: 'CB Policy Added',
+ 2503: 'CB Policy Removed',
+ 2504: 'CB Default Policy Set',
+ 2505: 'CB Heuristics Option Set',
+ 2506: 'CB Heuristics State Cleared',
+ 2600: 'Agent Watchdog Added',
+ 2601: 'Agent Watchdog Removed',
+ 2602: 'Agent Watchdog Action Set',
+ 2700: 'Wireless Profile Added',
+ 2701: 'Wireless Profile Removed',
+ 2702: 'Wireless Profile Updated',
+ 2800: 'EAC Posture Signer SET',
+ 2801: 'EAC Enabled',
+ 2802: 'EAC Disabled',
+ 2803: 'EAC Posture State',
+ 2804: 'EAC Set Options',
+ 2900: 'KVM Opt-in Enabled',
+ 2901: 'KVM Opt-in Disabled',
+ 2902: 'KVM Password Changed',
+ 2903: 'KVM Consent Succeeded',
+ 2904: 'KVM Consent Failed',
+ 3000: 'Opt-In Policy Change',
+ 3001: 'Send Consent Code Event',
+ 3002: 'Start Opt-In Blocked Event'
+ }
+
+ // Return human readable extended audit log data
+ // TODO: Just put some of them here, but many more still need to be added, helpful link here:
+ // https://software.intel.com/sites/manageability/AMT_Implementation_and_Reference_Guide/default.htm?turl=WordDocuments%2Fsecurityadminevents.htm
+ obj.GetAuditLogExtendedDataStr = function (id, data) {
+ if ((id == 1602 || id == 1604) && data.charCodeAt(0) == 0) { return data.substring(2, 2 + data.charCodeAt(1)); } // ACL Entry Added/Removed (Digest)
+ if (id == 1603) { if (data.charCodeAt(1) == 0) { return data.substring(3); } return null; } // ACL Entry Modified
+ if (id == 1605) { return ["Invalid ME access", "Invalid MEBx access"][data.charCodeAt(0)]; } // ACL Access with Invalid Credentials
+ if (id == 1606) { var r = ["Disabled", "Enabled"][data.charCodeAt(0)]; if (data.charCodeAt(1) == 0) { r += ", " + data.substring(3); } return r;} // ACL Entry State
+ if (id == 1607) { return "Remote " + ["NoAuth", "ServerAuth", "MutualAuth"][data.charCodeAt(0)] + ", Local " + ["NoAuth", "ServerAuth", "MutualAuth"][data.charCodeAt(1)]; } // TLS State Changed
+ if (id == 1617) { return obj.RealmNames[ReadInt(data, 0)] + ", " + ["NoAuth", "Auth", "Disabled"][data.charCodeAt(4)]; } // Set Realm Authentication Mode
+ if (id == 1619) { return ["BIOS", "MEBx", "Local MEI", "Local WSMAN", "Remote WSAMN"][data.charCodeAt(0)]; } // Intel AMT Unprovisioning Started
+ if (id == 1900) { return "From " + ReadShort(data, 0) + "." + ReadShort(data, 2) + "." + ReadShort(data, 4) + "." + ReadShort(data, 6) + " to " + ReadShort(data, 8) + "." + ReadShort(data, 10) + "." + ReadShort(data, 12) + "." + ReadShort(data, 14); } // Firmware Updated
+ if (id == 2100) { var t4 = new Date(); t4.setTime(ReadInt(data, 0) * 1000 + (new Date().getTimezoneOffset() * 60000)); return t4.toLocaleString(); } // Intel AMT Time Set
+ if (id == 3000) { return "From " + ["None", "KVM", "All"][data.charCodeAt(0)] + " to " + ["None", "KVM", "All"][data.charCodeAt(1)]; } // Opt-In Policy Change
+ if (id == 3001) { return ["Success", "Failed 3 times"][data.charCodeAt(0)]; } // Send Consent Code Event
+ return null;
+ }
+
+ obj.GetAuditLog = function (func) {
+ obj.AMT_AuditLog_ReadRecords(1, _GetAuditLog0, [func, []]);
+ }
+
+ function _GetAuditLog0(stack, name, responses, status, tag) {
+ if (status != 200) { tag[0](obj, [], status); return; }
+ var ptr, i, e, x, r = tag[1], t = new Date(), TimeStamp;
+
+ if (responses.Body['RecordsReturned'] > 0) {
+ responses.Body['EventRecords'] = MakeToArray(responses.Body['EventRecords']);
+
+ for (i in responses.Body['EventRecords']) {
+ e = null;
+ try {
+ e = window.atob(responses.Body['EventRecords'][i]);
+ } catch (e) {
+ console.log(e + " " + responses.Body['EventRecords'][i])
+ }
+ x = { 'AuditAppID': ReadShort(e, 0), 'EventID': ReadShort(e, 2), 'InitiatorType': e.charCodeAt(4) };
+ x['AuditApp'] = _AmtAuditStringTable[x['AuditAppID']];
+ x['Event'] = _AmtAuditStringTable[(x['AuditAppID'] * 100) + x['EventID']];
+ if (!x['Event']) x['Event'] = '#' + x['EventID'];
+
+ // Read and process the initiator
+ if (x['InitiatorType'] == 0) {
+ // HTTP digest
+ var userlen = e.charCodeAt(5);
+ x['Initiator'] = e.substring(6, 6 + userlen);
+ ptr = 6 + userlen;
+ }
+ if (x['InitiatorType'] == 1) {
+ // Kerberos
+ x['KerberosUserInDomain'] = ReadInt(e, 5);
+ var userlen = e.charCodeAt(9);
+ x['Initiator'] = GetSidString(e.substring(10, 10 + userlen));
+ ptr = 10 + userlen;
+ }
+ if (x['InitiatorType'] == 2) {
+ // Local
+ x['Initiator'] = 'Local';
+ ptr = 5;
+ }
+ if (x['InitiatorType'] == 3) {
+ // KVM Default Port
+ x['Initiator'] = 'KVM Default Port';
+ ptr = 5;
+ }
+
+ // Read timestamp
+ TimeStamp = ReadInt(e, ptr);
+ x['Time'] = new Date((TimeStamp + (t.getTimezoneOffset() * 60)) * 1000);
+ ptr += 4;
+
+ // Read network access
+ x['MCLocationType'] = e.charCodeAt(ptr++);
+ var netlen = e.charCodeAt(ptr++);
+ x['NetAddress'] = e.substring(ptr, ptr + netlen);
+
+ // Read extended data
+ ptr += netlen;
+ var exlen = e.charCodeAt(ptr++);
+ x['Ex'] = e.substring(ptr, ptr + exlen);
+ x['ExStr'] = obj.GetAuditLogExtendedDataStr((x['AuditAppID'] * 100) + x['EventID'], x['Ex']);
+
+ r.push(x);
+ }
+ }
+ if (responses.Body['TotalRecordCount'] > r.length) {
+ obj.AMT_AuditLog_ReadRecords(r.length + 1, _GetAuditLog0, [tag[0], r]);
+ } else {
+ tag[0](obj, r, status);
+ }
+ }
+
+ // ###END###{AuditLog}
+
+ return obj;
+}
+
+
+// ###BEGIN###{Certificates}
+
+// Forge MD5
+function hex_md5(str) { if (str == null) { str = ''; } return forge.md.md5.create().update(str).digest().toHex(); }
+
+// ###END###{Certificates}
+
+// ###BEGIN###{!Certificates}
+
+// TinyMD5 from https://github.com/jbt/js-crypto
+
+// Perform MD5 setup
+var md5_k = [];
+for (var i = 0; i < 64;) { md5_k[i] = 0 | (Math.abs(Math.sin(++i)) * 4294967296); }
+
+// Perform MD5 on raw string and return hex
+function hex_md5(str) {
+ if (str == null) { str = ''; }
+ var b, c, d, j,
+ x = [],
+ str2 = unescape(encodeURI(str)),
+ a = str2.length,
+ h = [b = 1732584193, c = -271733879, ~b, ~c],
+ i = 0;
+
+ for (; i <= a;) x[i >> 2] |= (str2.charCodeAt(i) || 128) << 8 * (i++ % 4);
+
+ x[str = (a + 8 >> 6) * 16 + 14] = a * 8;
+ i = 0;
+
+ for (; i < str; i += 16) {
+ a = h; j = 0;
+ for (; j < 64;) {
+ a = [
+ d = a[3],
+ ((b = a[1] | 0) +
+ ((d = (
+ (a[0] +
+ [
+ b & (c = a[2]) | ~b & d,
+ d & b | ~d & c,
+ b ^ c ^ d,
+ c ^ (b | ~d)
+ ][a = j >> 4]
+ ) +
+ (md5_k[j] +
+ (x[[
+ j,
+ 5 * j + 1,
+ 3 * j + 5,
+ 7 * j
+ ][a] % 16 + i] | 0)
+ )
+ )) << (a = [
+ 7, 12, 17, 22,
+ 5, 9, 14, 20,
+ 4, 11, 16, 23,
+ 6, 10, 15, 21
+ ][4 * a + j++ % 4]) | d >>> 32 - a)
+ ),
+ b,
+ c
+ ];
+ }
+ for (j = 4; j;) h[--j] = h[j] + a[j];
+ }
+
+ str = '';
+ for (; j < 32;) str += ((h[j >> 3] >> ((1 ^ j++ & 7) * 4)) & 15).toString(16);
+ return str;
+}
+
+// ###END###{!Certificates}
+
+// Perform MD5 on raw string and return raw string result
+function rstr_md5(str) { return hex2rstr(hex_md5(str)); }
+
+/*
+Convert arguments into selector set and body XML. Used by AMT_WiFiPortConfigurationService_UpdateWiFiSettings.
+args = {
+ "WiFiEndpoint": {
+ __parameterType: 'reference',
+ __resourceUri: 'http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_WiFiEndpoint',
+ Name: 'WiFi Endpoint 0'
+ },
+ "WiFiEndpointSettingsInput":
+ {
+ __parameterType: 'instance',
+ __namespace: 'http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_WiFiEndpointSettings',
+ ElementName: document.querySelector('#editProfile-profileName').value,
+ InstanceID: 'Intel(r) AMT:WiFi Endpoint Settings ' + document.querySelector('#editProfile-profileName').value,
+ AuthenticationMethod: document.querySelector('#editProfile-networkAuthentication').value,
+ //BSSType: 3, // Intel(r) AMT supports only infrastructure networks
+ EncryptionMethod: document.querySelector('#editProfile-encryption').value,
+ SSID: document.querySelector('#editProfile-networkName').value,
+ Priority: 100,
+ PSKPassPhrase: document.querySelector('#editProfile-passPhrase').value
+ },
+ "IEEE8021xSettingsInput": null,
+ "ClientCredential": null,
+ "CACredential": null
+},
+*/
+function execArgumentsToXml(args) {
+ if(args === undefined || args === null) return null;
+
+ var result = '';
+ for(var argName in args) {
+ var arg = args[argName];
+ if(!arg) continue;
+ if(arg['__parameterType'] === 'reference') result += referenceToXml(argName, arg);
+ else result += instanceToXml(argName, arg);
+ //if(arg['__isInstance']) result += instanceToXml(argName, arg);
+ }
+ return result;
+}
+
+/**
+ * Convert JavaScript object into XML
+
+
+ Wireless-Profile-Admin
+ Intel(r) AMT:WiFi Endpoint Settings Wireless-Profile-Admin
+ 6
+ 4
+ 100
+ xxxxxxxx
+
+ */
+function instanceToXml(instanceName, inInstance) {
+ if(inInstance === undefined || inInstance === null) return null;
+
+ var hasNamespace = !!inInstance['__namespace'];
+ var startTag = hasNamespace ? '';
+ for(var prop in inInstance) {
+ if (!inInstance.hasOwnProperty(prop) || prop.indexOf('__') === 0) continue;
+
+ if (typeof inInstance[prop] === 'function' || Array.isArray(inInstance[prop]) ) continue;
+
+ if (typeof inInstance[prop] === 'object') {
+ //result += startTag + prop +'>' + instanceToXml('prop', inInstance[prop]) + endTag + prop +'>';
+ console.error('only convert one level down...');
+ }
+ else {
+ result += startTag + prop +'>' + inInstance[prop].toString() + endTag + prop +'>';
+ }
+ }
+ result += '';
+ return result;
+}
+
+
+/**
+ * Convert a selector set into XML. Expect no nesting.
+ * {
+ * selectorName : selectorValue,
+ * selectorName : selectorValue,
+ * ... ...
+ * }
+
+
+ http://192.168.1.103:16992/wsman
+
+ http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_WiFiEndpoint
+
+ WiFi Endpoint 0
+
+
+
+
+ */
+function referenceToXml(referenceName, inReference) {
+ if(inReference === undefined || inReference === null ) return null;
+
+ var result = '/wsman'+ inReference['__resourceUri']+'';
+ for(var selectorName in inReference) {
+ if (!inReference.hasOwnProperty(selectorName) || selectorName.indexOf('__') === 0) continue;
+
+ if (typeof inReference[selectorName] === 'function' ||
+ typeof inReference[selectorName] === 'object' ||
+ Array.isArray(inReference[selectorName]) )
+ continue;
+
+ result += '' + inReference[selectorName].toString() + '';
+ }
+
+ result += '';
+ return result;
+}
+
+// Convert a byte array of SID into string
+function GetSidString(sid) {
+ var r = "S-" + sid.charCodeAt(0) + "-" + sid.charCodeAt(7);
+ for (var i = 2; i < (sid.length / 4) ; i++) r += "-" + ReadIntX(sid, i * 4);
+ return r;
+}
+
+// Convert a SID readable string into bytes
+function GetSidByteArray(sidString) {
+ if (!sidString || sidString == null) return null;
+ var sidParts = sidString.split('-');
+
+ // Make sure the SID has at least 4 parts and starts with 'S'
+ if (sidParts.length < 4 || (sidParts[0] != 's' && sidParts[0] != 'S')) return null;
+
+ // Check that each part of the SID is really an integer
+ for (var i = 1; i < sidParts.length; i++) { var y = parseInt(sidParts[i]); if (y != sidParts[i]) return null; sidParts[i] = y; }
+
+ // Version (8 bit) + Id count (8 bit) + 48 bit in big endian -- DO NOT use bitwise right shift operator. JavaScript converts the number into a 32 bit integer before shifting. In real world, it's highly likely this part is always 0.
+ var r = String.fromCharCode(sidParts[1]) + String.fromCharCode(sidParts.length - 3) + ShortToStr(Math.floor(sidParts[2] / Math.pow(2, 32))) + IntToStr((sidParts[2]) & 0xFFFF);
+
+ // the rest are in 32 bit in little endian
+ for (var i = 3; i < sidParts.length; i++) r += IntToStrX(sidParts[i]);
+ return r;
+}
diff --git a/amt-certificates-0.0.1.js b/amt-certificates-0.0.1.js
new file mode 100644
index 0000000..b5b767d
--- /dev/null
+++ b/amt-certificates-0.0.1.js
@@ -0,0 +1,181 @@
+/**
+* @fileoverview Intel(r) AMT Certificate functions
+* @author Ylian Saint-Hilaire
+* @version v0.2.0b
+*/
+
+// Check which key pair matches the public key in the certificate
+function amtcert_linkCertPrivateKey(certs, keys) {
+ for (var i in certs) {
+ var cert = certs[i];
+ try {
+ if (xxCertPrivateKeys.length == 0) return;
+ var publicKeyPEM = forge.pki.publicKeyToPem(forge.pki.certificateFromAsn1(forge.asn1.fromDer(cert.X509Certificate)).publicKey).substring(28 + 32).replace(/(\r\n|\n|\r)/gm, "");
+ for (var j = 0; j < keys.length; j++) {
+ if (publicKeyPEM === (keys[j]['DERKey'] + '-----END PUBLIC KEY-----')) {
+ keys[j].XCert = cert; // Link the key pair to the certificate
+ cert.XPrivateKey = keys[j]; // Link the certificate to the key pair
+ }
+ }
+ } catch (e) { console.log(e); }
+ }
+}
+
+// Load a P12 file, decodes it using the password and returns the private key handle
+function amtcert_loadP12File(file, password, func) {
+ try {
+ // Encode in Base64 so Forge API can parse it.
+ var p12Der = window.forge.util.decode64(btoa(file));
+ var p12Asn1 = window.forge.asn1.fromDer(p12Der);
+ var p12 = window.forge.pkcs12.pkcs12FromAsn1(p12Asn1, password);
+
+ // Private key is stored in a shrouded key bag
+ var bags = p12.getBags({ bagType: window.forge.pki.oids.pkcs8ShroudedKeyBag });
+ console.assert(bags[window.forge.pki.oids.pkcs8ShroudedKeyBag] && bags[window.forge.pki.oids.pkcs8ShroudedKeyBag].length > 0);
+
+ // Import the Forge private key structure into Web Crypto
+ var privateKey = bags[window.forge.pki.oids.pkcs8ShroudedKeyBag][0].key;
+ var rsaPrivateKey = window.forge.pki.privateKeyToAsn1(privateKey);
+ var privateKeyInfo = window.forge.pki.wrapRsaPrivateKey(rsaPrivateKey);
+ var pkcs8 = window.forge.asn1.toDer(privateKeyInfo).getBytes();
+
+ // Get the issuer attributes
+ var certBags = p12.getBags({ bagType: window.forge.pki.oids.certBag });
+ var issuerAttributes = certBags[window.forge.pki.oids.certBag][0].cert.subject.attributes;
+
+ var bags1 = p12.getBags({ bagType: forge.pki.oids.certBag });
+ var cert = bags1[forge.pki.oids.certBag][0].cert;
+
+ func(privateKey, issuerAttributes, cert);
+ return true;
+ } catch (ex) { }
+ return false;
+}
+
+function amtcert_signWithCaKey(DERKey, caPrivateKey, certAttributes, issuerAttributes, extKeyUsage) {
+ if (!caPrivateKey || caPrivateKey == null) {
+ var certAndKey = amtcert_createCertificate(issuerAttributes);
+ caPrivateKey = certAndKey.key;
+ }
+ return amtcert_createCertificate(certAttributes, caPrivateKey, DERKey, issuerAttributes, extKeyUsage);
+}
+
+// --- Extended Key Usage OID's ---
+// 1.3.6.1.5.5.7.3.1 = TLS Server certificate
+// 1.3.6.1.5.5.7.3.2 = TLS Client certificate
+// 2.16.840.1.113741.1.2.1 = Intel AMT Remote Console
+// 2.16.840.1.113741.1.2.2 = Intel AMT Local Console
+// 2.16.840.1.113741.1.2.3 = Intel AMT Client Setup Certificate (Zero-Touch)
+
+// Generate a certificate with a set of attributes signed by a rootCert. If the rootCert is obmitted, the generated certificate is self-signed.
+function amtcert_createCertificate(certAttributes, caPrivateKey, DERKey, issuerAttributes, extKeyUsage) {
+ // Generate a keypair and create an X.509v3 certificate
+ var keys, cert = forge.pki.createCertificate();
+ if (!DERKey) {
+ keys = forge.pki.rsa.generateKeyPair(2048);
+ cert.publicKey = keys.publicKey;
+ } else {
+ cert.publicKey = forge.pki.publicKeyFromPem('-----BEGIN PUBLIC KEY-----' + DERKey + '-----END PUBLIC KEY-----');
+ }
+ cert.serialNumber = '' + Math.floor((Math.random() * 100000) + 1);
+ cert.validity.notBefore = new Date(2018, 0, 1);
+ //cert.validity.notBefore.setFullYear(cert.validity.notBefore.getFullYear() - 1); // Create a certificate that is valid one year before, to make sure out-of-sync clocks don't reject this cert.
+ cert.validity.notAfter = new Date(2049, 11, 31);
+ //cert.validity.notAfter.setFullYear(cert.validity.notAfter.getFullYear() + 20);
+ var attrs = [];
+ if (certAttributes['CN']) attrs.push({ name: 'commonName', value: certAttributes['CN'] });
+ if (certAttributes['C']) attrs.push({ name: 'countryName', value: certAttributes['C'] });
+ if (certAttributes['ST']) attrs.push({ shortName: 'ST', value: certAttributes['ST'] });
+ if (certAttributes['O']) attrs.push({ name: 'organizationName', value: certAttributes['O'] });
+ cert.setSubject(attrs);
+
+ if (caPrivateKey) {
+ // Use root attributes
+ var rootattrs = [];
+ if (issuerAttributes['CN']) rootattrs.push({ name: 'commonName', value: issuerAttributes['CN'] });
+ if (issuerAttributes['C']) rootattrs.push({ name: 'countryName', value: issuerAttributes['C'] });
+ if (issuerAttributes['ST']) rootattrs.push({ shortName: 'ST', value: issuerAttributes['ST'] });
+ if (issuerAttributes['O']) rootattrs.push({ name: 'organizationName', value: issuerAttributes['O'] });
+ cert.setIssuer(rootattrs);
+ } else {
+ // Use our own attributes
+ cert.setIssuer(attrs);
+ }
+
+ if (caPrivateKey == undefined) {
+ // Create a root certificate
+ cert.setExtensions([{
+ name: 'basicConstraints',
+ cA: true
+ }, {
+ name: 'nsCertType',
+ sslCA: true,
+ emailCA: true,
+ objCA: true
+ }, {
+ name: 'subjectKeyIdentifier'
+ }]);
+ } else {
+ if (extKeyUsage == null) { extKeyUsage = { name: 'extKeyUsage', serverAuth: true, } } else { extKeyUsage.name = 'extKeyUsage'; }
+
+ /*
+ {
+ name: 'extKeyUsage',
+ serverAuth: true,
+ clientAuth: true,
+ codeSigning: true,
+ emailProtection: true,
+ timeStamping: true,
+ '2.16.840.1.113741.1.2.1': true
+ }
+ */
+
+ // Create a leaf certificate
+ cert.setExtensions([{
+ name: 'basicConstraints'
+ }, {
+ name: 'keyUsage',
+ keyCertSign: true,
+ digitalSignature: true,
+ nonRepudiation: true,
+ keyEncipherment: true,
+ dataEncipherment: true
+ }, extKeyUsage, {
+ name: 'nsCertType',
+ client: true,
+ server: true,
+ email: true,
+ objsign: true,
+ }, {
+ name: 'subjectKeyIdentifier'
+ }]);
+ }
+
+ // Self-sign certificate
+ if (caPrivateKey) {
+ cert.sign(caPrivateKey, forge.md.sha256.create());
+ } else {
+ cert.sign(keys.privateKey, forge.md.sha256.create());
+ }
+
+ if (DERKey) {
+ return cert;
+ } else {
+ return { 'cert': cert, 'key': keys.privateKey };
+ }
+}
+
+function _stringToArrayBuffer(str) {
+ var buf = new ArrayBuffer(str.length);
+ var bufView = new Uint8Array(buf);
+ for (var i = 0, strLen = str.length; i < strLen; i++) { bufView[i] = str.charCodeAt(i); }
+ return buf;
+}
+
+function _arrayBufferToString(buffer) {
+ var binary = '';
+ var bytes = new Uint8Array(buffer);
+ var len = bytes.byteLength;
+ for (var i = 0; i < len; i++) { binary += String.fromCharCode(bytes[i]); }
+ return binary;
+}
diff --git a/amt-desktop-0.0.2.js b/amt-desktop-0.0.2.js
new file mode 100644
index 0000000..42aefa8
--- /dev/null
+++ b/amt-desktop-0.0.2.js
@@ -0,0 +1,923 @@
+/**
+* @description Remote Desktop
+* @author Ylian Saint-Hilaire
+* @version v0.0.2g
+*/
+
+// Construct a MeshServer object
+var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
+ var obj = {};
+ obj.canvasid = divid;
+ obj.scrolldiv = scrolldiv;
+ obj.canvas = Q(divid).getContext("2d");
+ obj.protocol = 2; // KVM
+ obj.state = 0;
+ obj.acc = "";
+ obj.ScreenWidth = 960;
+ obj.ScreenHeight = 700;
+ obj.width = 0;
+ obj.height = 0;
+ obj.rwidth = 0;
+ obj.rheight = 0;
+ obj.bpp = 2; // Bytes per pixel (1 or 2 supported)
+ obj.graymode = 0; // 0 = Color, 1 = 256 grays, 2 = 16 grays. obj.bbp must be 1 in gray modes.
+ obj.useZRLE = true;
+ obj.showmouse = true;
+ obj.buttonmask = 0;
+ //obj.inbytes = 0;
+ //obj.outbytes = 0;
+ obj.spare = null;
+ obj.sparew = 0;
+ obj.spareh = 0;
+ obj.sparew2 = 0;
+ obj.spareh2 = 0;
+ obj.sparecache = {};
+ obj.ZRLEfirst = 1;
+ obj.onScreenSizeChange = null;
+ obj.frameRateDelay = 0;
+ // ###BEGIN###{DesktopRotation}
+ obj.noMouseRotate = false;
+ obj.rotation = 0;
+ // ###END###{DesktopRotation}
+ // ###BEGIN###{DesktopInband}
+ obj.kvmDataSupported = false;
+ obj.onKvmData = null;
+ obj.onKvmDataPending = [];
+ obj.onKvmDataAck = -1;
+ obj.holding = false;
+ obj.lastKeepAlive = Date.now();
+ // ###END###{DesktopInband}
+
+ obj.mNagleTimer = null; // Mouse motion slowdown timer
+ obj.mx = 0; // Last mouse x position
+ obj.my = 0; // Last mouse y position
+ // ###BEGIN###{DesktopFocus}
+ obj.ox = -1; // Old mouse x position
+ obj.oy = -1; // Old mouse y position
+ obj.focusmode = 0;
+ // ###END###{DesktopFocus}
+ // ###BEGIN###{Inflate}
+ obj.inflate = ZLIB.inflateInit(-15);
+ // ###END###{Inflate}
+
+ // Private method
+ obj.Debug = function (msg) { console.log(msg); }
+
+ obj.xxStateChange = function (newstate) {
+ if (newstate == 0) {
+ obj.canvas.fillStyle = '#000000';
+ obj.canvas.fillRect(0, 0, obj.width, obj.height);
+ obj.canvas.canvas.width = obj.rwidth = obj.width = 640;
+ obj.canvas.canvas.height = obj.rheight = obj.height = 400;
+ QS(obj.canvasid).cursor = 'auto';
+ // ###BEGIN###{Inflate}
+ obj.inflate = ZLIB.inflateInit(-15); // Reset inflate
+ // ###END###{Inflate}
+ } else {
+ if (!obj.showmouse) { QS(obj.canvasid).cursor = 'none'; }
+ }
+ }
+
+ obj.ProcessData = function (data) {
+ if (!data) return;
+ // obj.Debug("KRecv(" + data.length + "): " + rstr2hex(data));
+ //obj.inbytes += data.length;
+ //obj.Debug("KRecv(" + obj.inbytes + ")");
+ obj.acc += data;
+ while (obj.acc.length > 0) {
+ //obj.Debug("KAcc(" + obj.acc.length + "): " + rstr2hex(obj.acc));
+ var cmdsize = 0;
+ if (obj.state == 0 && obj.acc.length >= 12) {
+ // Getting handshake & version
+ cmdsize = 12;
+ //if (obj.acc.substring(0, 4) != "RFB ") { return obj.Stop(); }
+ //var version = parseFloat(obj.acc.substring(4, 11));
+ //obj.Debug("KVersion: " + version);
+ obj.state = 1;
+ obj.Send("RFB 003.008\n");
+ }
+ else if (obj.state == 1 && obj.acc.length >= 1) {
+ // Getting security options
+ cmdsize = obj.acc.charCodeAt(0) + 1;
+ obj.Send(String.fromCharCode(1)); // Send the "None" security type. Since we already authenticated using redirection digest auth, we don't need to do this again.
+ obj.state = 2;
+ }
+ else if (obj.state == 2 && obj.acc.length >= 4) {
+ // Getting security response
+ cmdsize = 4;
+ if (ReadInt(obj.acc, 0) != 0) { return obj.Stop(); }
+ obj.Send(String.fromCharCode(1)); // Send share desktop flag
+ obj.state = 3;
+ }
+ else if (obj.state == 3 && obj.acc.length >= 24) {
+ // Getting server init
+ // ###BEGIN###{DesktopRotation}
+ obj.rotation = 0; // We don't currently support screen init while rotated.
+ // ###END###{DesktopRotation}
+ var namelen = ReadInt(obj.acc, 20);
+ if (obj.acc.length < 24 + namelen) return;
+ cmdsize = 24 + namelen;
+ obj.canvas.canvas.width = obj.rwidth = obj.width = obj.ScreenWidth = ReadShort(obj.acc, 0);
+ obj.canvas.canvas.height = obj.rheight = obj.height = obj.ScreenHeight = ReadShort(obj.acc, 2);
+
+ // These are all values we don't really need, we are going to only run in RGB565 or RGB332 and not use the flexibility provided by these settings.
+ // Makes the javascript code smaller and maybe a bit faster.
+ /*
+ obj.xbpp = obj.acc.charCodeAt(4);
+ obj.depth = obj.acc.charCodeAt(5);
+ obj.bigend = obj.acc.charCodeAt(6);
+ obj.truecolor = obj.acc.charCodeAt(7);
+ obj.rmax = ReadShort(obj.acc, 8);
+ obj.gmax = ReadShort(obj.acc, 10);
+ obj.bmax = ReadShort(obj.acc, 12);
+ obj.rsh = obj.acc.charCodeAt(14);
+ obj.gsh = obj.acc.charCodeAt(15);
+ obj.bsh = obj.acc.charCodeAt(16);
+ var name = obj.acc.substring(24, 24 + namelen);
+ obj.Debug("name: " + name);
+ obj.Debug("width: " + obj.width + ", height: " + obj.height);
+ obj.Debug("bits-per-pixel: " + obj.xbpp);
+ obj.Debug("depth: " + obj.depth);
+ obj.Debug("big-endian-flag: " + obj.bigend);
+ obj.Debug("true-colour-flag: " + obj.truecolor);
+ obj.Debug("rgb max: " + obj.rmax + "," + obj.gmax + "," + obj.bmax);
+ obj.Debug("rgb shift: " + obj.rsh + "," + obj.gsh + "," + obj.bsh);
+ */
+
+ // SetEncodings, with AMT we can't omit RAW, must be specified.
+ // Intel AMT supports encodings: RAW (0), ZRLE (16), Desktop Size (0xFFFFFF21, -223), KVM Data Channel (1092)
+
+ var supportedEncodings = '';
+ if (obj.useZRLE) supportedEncodings += IntToStr(16);
+ supportedEncodings += IntToStr(0);
+ // ###BEGIN###{DesktopInband}
+ supportedEncodings += IntToStr(1092);
+ // ###END###{DesktopInband}
+
+ obj.Send(String.fromCharCode(2, 0) + ShortToStr((supportedEncodings.length / 4) + 1) + supportedEncodings + IntToStr(-223)); // Supported Encodings + Desktop Size
+
+ if (obj.graymode == 0) {
+ // Set the pixel encoding to something much smaller
+ // obj.Send(String.fromCharCode(0, 0, 0, 0, 16, 16, 0, 1) + ShortToStr(31) + ShortToStr(63) + ShortToStr(31) + String.fromCharCode(11, 5, 0, 0, 0, 0)); // Setup 16 bit color RGB565 (This is the default, so we don't need to set it)
+ if (obj.bpp == 1) obj.Send(String.fromCharCode(0, 0, 0, 0, 8, 8, 0, 1) + ShortToStr(7) + ShortToStr(7) + ShortToStr(3) + String.fromCharCode(5, 2, 0, 0, 0, 0)); // Setup 8 bit color RGB332
+ } else {
+ obj.bpp = 1;
+ if (obj.graymode == 1) { obj.Send(String.fromCharCode(0, 0, 0, 0, 8, 8, 0, 1) + ShortToStr(255) + ShortToStr(0) + ShortToStr(0) + String.fromCharCode(0, 0, 0, 0, 0, 0)); } // Setup 8 bit gray RGB800
+ if (obj.graymode == 2) { obj.Send(String.fromCharCode(0, 0, 0, 0, 8, 8, 0, 1) + ShortToStr(15) + ShortToStr(0) + ShortToStr(0) + String.fromCharCode(0, 0, 0, 0, 0, 0)); } // Setup 4 bit gray RGB400
+ }
+
+ obj.state = 4;
+ if (obj.parent) { obj.parent.xxStateChange(3); }
+ _SendRefresh();
+ //obj.timer = setInterval(obj.xxOnTimer, 50);
+
+ // ###BEGIN###{DesktopFocus}
+ obj.ox = -1; // Old mouse x position
+ // ###END###{DesktopFocus}
+
+ if (obj.onScreenSizeChange != null) { obj.onScreenSizeChange(obj, obj.ScreenWidth, obj.ScreenHeight); }
+ }
+ else if (obj.state == 4) {
+ switch (obj.acc.charCodeAt(0)) {
+ case 0: // FramebufferUpdate
+ if (obj.acc.length < 4) return;
+ obj.state = 100 + ReadShort(obj.acc, 2); // Read the number of tiles that are going to be sent, add 100 and use that as our protocol state.
+ cmdsize = 4;
+ break;
+ case 2: // This is the bell, do nothing.
+ cmdsize = 1;
+ break;
+ case 3: // This is ServerCutText
+ if (obj.acc.length < 8) return;
+ var len = ReadInt(obj.acc, 4) + 8;
+ if (obj.acc.length < len) return;
+ cmdsize = handleServerCutText(obj.acc);
+ break;
+ }
+ }
+ else if (obj.state > 100 && obj.acc.length >= 12) {
+ var x = ReadShort(obj.acc, 0),
+ y = ReadShort(obj.acc, 2),
+ width = ReadShort(obj.acc, 4),
+ height = ReadShort(obj.acc, 6),
+ s = width * height,
+ encoding = ReadInt(obj.acc, 8);
+
+ if (encoding < 17) {
+ if (width < 1 || width > 64 || height < 1 || height > 64) { console.log("Invalid tile size (" + width + "," + height + "), disconnecting."); return obj.Stop(); }
+
+ // Set the spare bitmap to the right size if it's not already. This allows us to recycle the spare most if not all the time.
+ if (obj.sparew != width || obj.spareh != height) {
+ obj.sparew = obj.sparew2 = width;
+ obj.spareh = obj.spareh2 = height;
+ // ###BEGIN###{DesktopRotation}
+ if (obj.rotation == 1 || obj.rotation == 3) { obj.sparew2 = height, obj.spareh2 = width; }
+ // ###END###{DesktopRotation}
+ var xspacecachename = obj.sparew2 + 'x' + obj.spareh2;
+ obj.spare = obj.sparecache[xspacecachename];
+ if (!obj.spare) {
+ obj.sparecache[xspacecachename] = obj.spare = obj.canvas.createImageData(obj.sparew2, obj.spareh2);
+ var j = (obj.sparew2 * obj.spareh2) << 2;
+ for (var i = 3; i < j; i += 4) { obj.spare.data[i] = 0xFF; } // Set alpha channel to opaque.
+ }
+ }
+
+ }
+
+ if (encoding == 0xFFFFFF21) {
+ // Desktop Size (0xFFFFFF21, -223)
+ obj.canvas.canvas.width = obj.ScreenWidth = obj.rwidth = obj.width = width;
+ obj.canvas.canvas.height = obj.ScreenHeight = obj.rheight = obj.height = height;
+ obj.Send(String.fromCharCode(3, 0, 0, 0, 0, 0) + ShortToStr(obj.width) + ShortToStr(obj.height)); // FramebufferUpdateRequest
+ cmdsize = 12;
+ if (obj.onScreenSizeChange != null) { obj.onScreenSizeChange(obj, obj.ScreenWidth, obj.ScreenHeight); }
+ // obj.Debug("New desktop width: " + obj.width + ", height: " + obj.height);
+ }
+ else if (encoding == 0) {
+ // RAW encoding
+ var ptr = 12, cs = 12 + (s * obj.bpp);
+ if (obj.acc.length < cs) return; // Check we have all the data needed and we can only draw 64x64 tiles.
+ cmdsize = cs;
+
+ // CRITICAL LOOP, optimize this as much as possible
+ if (obj.bpp == 2) {
+ for (var i = 0; i < s; i++) { _setPixel16(obj.acc.charCodeAt(ptr++) + (obj.acc.charCodeAt(ptr++) << 8), i); }
+ } else {
+ for (var i = 0; i < s; i++) { _setPixel8(obj.acc.charCodeAt(ptr++), i); }
+ }
+ _putImage(obj.spare, x, y);
+ }
+ else if (encoding == 16) {
+ // ZRLE encoding
+ if (obj.acc.length < 16) return;
+ var datalen = ReadInt(obj.acc, 12);
+ if (obj.acc.length < (16 + datalen)) return;
+ //obj.Debug("RECT ZRLE (" + x + "," + y + "," + width + "," + height + ") LEN = " + datalen);
+ //obj.Debug("RECT ZRLE LEN: " + ReadShortX(obj.acc, 17) + ", DATA: " + rstr2hex(obj.acc.substring(16)));
+
+ // Process the ZLib header if this is the first block
+ var ptr = 16, delta = 5, dx = 0;
+
+ if (datalen > 5 && obj.acc.charCodeAt(ptr) == 0 && ReadShortX(obj.acc, ptr + 1) == (datalen - delta)) {
+ // This is an uncompressed ZLib data block
+ _decodeLRE(obj.acc, ptr + 5, x, y, width, height, s, datalen);
+ }
+ // ###BEGIN###{Inflate}
+ else {
+ // This is compressed ZLib data, decompress and process it.
+ var arr = obj.inflate.inflate(obj.acc.substring(ptr, ptr + datalen - dx));
+ if (arr.length > 0) { _decodeLRE(arr, 0, x, y, width, height, s, arr.length); } else { obj.Debug("Invalid deflate data"); }
+ }
+ // ###END###{Inflate}
+
+ cmdsize = 16 + datalen;
+ } else {
+ obj.Debug('Unknown Encoding: ' + encoding + ', HEX: ' + rstr2hex(obj.acc));
+ return obj.Stop();
+ }
+ if (--obj.state == 100) {
+ obj.state = 4;
+ if (obj.frameRateDelay == 0) {
+ _SendRefresh(); // Ask for new frame
+ } else {
+ setTimeout(_SendRefresh, obj.frameRateDelay); // Hold x miliseconds before asking for a new frame
+ }
+ }
+ }
+
+ if (cmdsize == 0) return;
+ obj.acc = obj.acc.substring(cmdsize);
+ }
+ }
+
+ function _decodeLRE(data, ptr, x, y, width, height, s, datalen) {
+ var subencoding = data.charCodeAt(ptr++), index, v, runlengthdecode, palette = {}, rlecount = 0, runlength = 0, i;
+ // obj.Debug("RECT RLE (" + (datalen - 5) + ", " + subencoding + "):" + rstr2hex(data.substring(21, 21 + (datalen - 5))));
+ if (subencoding == 0) {
+ // RAW encoding
+ if (obj.bpp == 2) {
+ for (i = 0; i < s; i++) { _setPixel16(data.charCodeAt(ptr++) + (data.charCodeAt(ptr++) << 8), i); }
+ } else {
+ for (i = 0; i < s; i++) { _setPixel8(data.charCodeAt(ptr++), i); }
+ }
+ _putImage(obj.spare, x, y);
+ }
+ else if (subencoding == 1) {
+ // Solid color tile
+ v = data.charCodeAt(ptr++) + ((obj.bpp == 2) ? (data.charCodeAt(ptr++) << 8) : 0);
+ obj.canvas.fillStyle = 'rgb(' + ((obj.bpp == 1) ? ((v & 224) + ',' + ((v & 28) << 3) + ',' + _fixColor((v & 3) << 6)) : (((v >> 8) & 248) + ',' + ((v >> 3) & 252) + ',' + ((v & 31) << 3))) + ')';
+
+ // ###BEGIN###{DesktopRotation}
+ var xx = _rotX(x, y);
+ y = _rotY(x, y);
+ x = xx;
+ // ###END###{DesktopRotation}
+
+ obj.canvas.fillRect(x, y, width, height);
+ }
+ else if (subencoding > 1 && subencoding < 17) { // Packed palette encoded tile
+ // Read the palette
+ var br = 4, bm = 15; // br is BitRead and bm is BitMask. By adjusting these two we can support all the variations in this encoding.
+ if (obj.bpp == 2) {
+ for (i = 0; i < subencoding; i++) { palette[i] = data.charCodeAt(ptr++) + (data.charCodeAt(ptr++) << 8); }
+ if (subencoding == 2) { br = 1; bm = 1; } else if (subencoding <= 4) { br = 2; bm = 3; } // Compute bits to read & bit mark
+ while (rlecount < s && ptr < data.length) { v = data.charCodeAt(ptr++); for (i = (8 - br) ; i >= 0; i -= br) { _setPixel16(palette[(v >> i) & bm], rlecount++); } } // Display all the bits
+ } else {
+ for (i = 0; i < subencoding; i++) { palette[i] = data.charCodeAt(ptr++); }
+ if (subencoding == 2) { br = 1; bm = 1; } else if (subencoding <= 4) { br = 2; bm = 3; } // Compute bits to read & bit mark
+ while (rlecount < s && ptr < data.length) { v = data.charCodeAt(ptr++); for (i = (8 - br) ; i >= 0; i -= br) { _setPixel8(palette[(v >> i) & bm], rlecount++); } } // Display all the bits
+ }
+ _putImage(obj.spare, x, y);
+ }
+ else if (subencoding == 128) { // RLE encoded tile
+ if (obj.bpp == 2) {
+ while (rlecount < s && ptr < data.length) {
+ // Get the run color
+ v = data.charCodeAt(ptr++) + (data.charCodeAt(ptr++) << 8);
+
+ // Decode the run length. This is the fastest and most compact way I found to do this.
+ runlength = 1; do { runlength += (runlengthdecode = data.charCodeAt(ptr++)); } while (runlengthdecode == 255);
+
+ // Draw a run
+ if (obj.rotation == 0) {
+ _setPixel16run(v, rlecount, runlength); rlecount += runlength;
+ } else {
+ while (--runlength >= 0) { _setPixel16(v, rlecount++); }
+ }
+ }
+ } else {
+ while (rlecount < s && ptr < data.length) {
+ // Get the run color
+ v = data.charCodeAt(ptr++);
+
+ // Decode the run length. This is the fastest and most compact way I found to do this.
+ runlength = 1; do { runlength += (runlengthdecode = data.charCodeAt(ptr++)); } while (runlengthdecode == 255);
+
+ // Draw a run
+ if (obj.rotation == 0) {
+ _setPixel8run(v, rlecount, runlength); rlecount += runlength;
+ } else {
+ while (--runlength >= 0) { _setPixel8(v, rlecount++); }
+ }
+ }
+ }
+ _putImage(obj.spare, x, y);
+ }
+ else if (subencoding > 129) { // Palette RLE encoded tile
+ // Read the palette
+ if (obj.bpp == 2) {
+ for (i = 0; i < (subencoding - 128) ; i++) { palette[i] = data.charCodeAt(ptr++) + (data.charCodeAt(ptr++) << 8); }
+ } else {
+ for (i = 0; i < (subencoding - 128) ; i++) { palette[i] = data.charCodeAt(ptr++); }
+ }
+
+ // Decode RLE on palette
+ while (rlecount < s && ptr < data.length) {
+ // Setup the run, get the color index and get the color from the palette.
+ runlength = 1; index = data.charCodeAt(ptr++); v = palette[index % 128];
+
+ // If the index starts with high order bit 1, this is a run and decode the run length.
+ if (index > 127) { do { runlength += (runlengthdecode = data.charCodeAt(ptr++)); } while (runlengthdecode == 255); }
+
+ // Draw a run
+ if (obj.rotation == 0) {
+ if (obj.bpp == 2) {
+ _setPixel16run(v, rlecount, runlength); rlecount += runlength;
+ } else {
+ _setPixel8run(v, rlecount, runlength); rlecount += runlength;
+ }
+ } else {
+ if (obj.bpp == 2) {
+ while (--runlength >= 0) { _setPixel16(v, rlecount++); }
+ } else {
+ while (--runlength >= 0) { _setPixel8(v, rlecount++); }
+ }
+ }
+ }
+ _putImage(obj.spare, x, y);
+ }
+ }
+
+ // ###BEGIN###{DesktopInband}
+ obj.hold = function (holding) {
+ if (obj.holding == holding) return;
+ obj.holding = holding;
+ obj.canvas.fillStyle = '#000000';
+ obj.canvas.fillRect(0, 0, obj.width, obj.height); // Paint black
+ if (obj.holding == false) {
+ // Go back to normal operations
+ // Set canvas size and ask for full screen refresh
+ if ((obj.canvas.canvas.width != obj.width) || (obj.canvas.canvas.height != obj.height)) {
+ obj.canvas.canvas.width = obj.width; obj.canvas.canvas.height = obj.height;
+ if (obj.onScreenSizeChange != null) { obj.onScreenSizeChange(obj, obj.ScreenWidth, obj.ScreenHeight); } // ???
+ }
+ obj.Send(String.fromCharCode(3, 0, 0, 0, 0, 0) + ShortToStr(obj.width) + ShortToStr(obj.height)); // FramebufferUpdateRequest
+ } else {
+ obj.UnGrabMouseInput();
+ obj.UnGrabKeyInput();
+ }
+ }
+ // ###END###{DesktopInband}
+
+ function _putImage(i, x, y) {
+ // ###BEGIN###{DesktopInband}
+ if (obj.holding == true) return;
+ // ###END###{DesktopInband}
+ // ###BEGIN###{DesktopRotation}
+ var xx = _arotX(x, y);
+ y = _arotY(x, y);
+ x = xx;
+ // ###END###{DesktopRotation}
+ obj.canvas.putImageData(i, x, y);
+ }
+
+ // Set 8bit color RGB332
+ function _setPixel8(v, p) {
+ var pp = p << 2;
+
+ // ###BEGIN###{DesktopRotation}
+ if (obj.rotation > 0) {
+ if (obj.rotation == 1) { var x = p % obj.sparew, y = Math.floor(p / obj.sparew); p = (x * obj.sparew2) + (obj.sparew2 - 1 - y); pp = p << 2; }
+ else if (obj.rotation == 2) { pp = (obj.sparew * obj.spareh * 4) - 4 - pp; }
+ else if (obj.rotation == 3) { var x = p % obj.sparew, y = Math.floor(p / obj.sparew); p = ((obj.sparew2 - 1 - x) * obj.sparew2) + (y); pp = p << 2; }
+ }
+ // ###END###{DesktopRotation}
+
+ if (obj.graymode == 0) {
+ obj.spare.data[pp] = v & 224;
+ obj.spare.data[pp + 1] = (v & 28) << 3;
+ obj.spare.data[pp + 2] = _fixColor((v & 3) << 6);
+ } else {
+ obj.spare.data[pp] = obj.spare.data[pp + 1] = obj.spare.data[pp + 2] = v;
+ }
+ }
+
+ // Set 16bit color RGB565
+ function _setPixel16(v, p) {
+ var pp = p << 2;
+
+ // ###BEGIN###{DesktopRotation}
+ if (obj.rotation > 0) {
+ if (obj.rotation == 1) { var x = p % obj.sparew, y = Math.floor(p / obj.sparew); p = (x * obj.sparew2) + (obj.sparew2 - 1 - y); pp = p << 2; }
+ else if (obj.rotation == 2) { pp = (obj.sparew * obj.spareh * 4) - 4 - pp; }
+ else if (obj.rotation == 3) { var x = p % obj.sparew, y = Math.floor(p / obj.sparew); p = ((obj.sparew2 - 1 - x) * obj.sparew2) + (y); pp = p << 2; }
+ }
+ // ###END###{DesktopRotation}
+
+ obj.spare.data[pp] = (v >> 8) & 248;
+ obj.spare.data[pp + 1] = (v >> 3) & 252;
+ obj.spare.data[pp + 2] = (v & 31) << 3;
+ }
+
+ // Set a run of 8bit color RGB332
+ function _setPixel8run(v, p, run) {
+ var pp = (p << 2), r = (v & 224), g = ((v & 28) << 3), b = (_fixColor((v & 3) << 6));
+ while (--run >= 0) { obj.spare.data[pp] = r; obj.spare.data[pp+1] = g; obj.spare.data[pp+2] = b; pp += 4; }
+ }
+
+ // Set a run of 16bit color RGB565
+ function _setPixel16run(v, p, run) {
+ var pp = (p << 2), r = ((v >> 8) & 248), g = ((v >> 3) & 252), b = ((v & 31) << 3);
+ while (--run >= 0) { obj.spare.data[pp] = r; obj.spare.data[pp+1] = g; obj.spare.data[pp+2] = b; pp += 4; }
+ }
+
+ // ###BEGIN###{DesktopRotation}
+ function _arotX(x, y) {
+ if (obj.rotation == 0) return x;
+ if (obj.rotation == 1) return obj.canvas.canvas.width - obj.sparew2 - y;
+ if (obj.rotation == 2) return obj.canvas.canvas.width - obj.sparew2 - x;
+ if (obj.rotation == 3) return y;
+ return 0;
+ }
+
+ function _arotY(x, y) {
+ if (obj.rotation == 0) return y;
+ if (obj.rotation == 1) return x;
+ if (obj.rotation == 2) return obj.canvas.canvas.height - obj.spareh2 - y;
+ if (obj.rotation == 3) return obj.canvas.canvas.height - obj.spareh - x;
+ return 0;
+ }
+
+ function _crotX(x, y) {
+ if (obj.rotation == 0) return x;
+ if (obj.rotation == 1) return y;
+ if (obj.rotation == 2) return obj.canvas.canvas.width - x;
+ if (obj.rotation == 3) return obj.canvas.canvas.height - y;
+ return 0;
+ }
+
+ function _crotY(x, y) {
+ if (obj.rotation == 0) return y;
+ if (obj.rotation == 1) return obj.canvas.canvas.width - x;
+ if (obj.rotation == 2) return obj.canvas.canvas.height - y;
+ if (obj.rotation == 3) return x;
+ return 0;
+ }
+
+ function _rotX(x, y) {
+ if (obj.rotation == 0) return x;
+ if (obj.rotation == 1) return x;
+ if (obj.rotation == 2) return x - obj.canvas.canvas.width;
+ if (obj.rotation == 3) return x - obj.canvas.canvas.height;
+ return 0;
+ }
+
+ function _rotY(x, y) {
+ if (obj.rotation == 0) return y;
+ if (obj.rotation == 1) return y - obj.canvas.canvas.width;
+ if (obj.rotation == 2) return y - obj.canvas.canvas.height;
+ if (obj.rotation == 3) return y;
+ return 0;
+ }
+
+ obj.tcanvas = null;
+ obj.setRotation = function (x) {
+ while (x < 0) { x += 4; }
+ var newrotation = x % 4;
+ //console.log('hard-rot: ' + newrotation);
+ // ###BEGIN###{DesktopInband}
+ if (obj.holding == true) { obj.rotation = newrotation; return; }
+ // ###END###{DesktopInband}
+
+ if (newrotation == obj.rotation) return true;
+ var rw = obj.canvas.canvas.width;
+ var rh = obj.canvas.canvas.height;
+ if (obj.rotation == 1 || obj.rotation == 3) { rw = obj.canvas.canvas.height; rh = obj.canvas.canvas.width; }
+
+ // Copy the canvas, put it back in the correct direction
+ if (obj.tcanvas == null) obj.tcanvas = document.createElement('canvas');
+ var tcanvasctx = obj.tcanvas.getContext('2d');
+ tcanvasctx.setTransform(1, 0, 0, 1, 0, 0);
+ tcanvasctx.canvas.width = rw;
+ tcanvasctx.canvas.height = rh;
+ tcanvasctx.rotate((obj.rotation * -90) * Math.PI / 180);
+ if (obj.rotation == 0) tcanvasctx.drawImage(obj.canvas.canvas, 0, 0);
+ if (obj.rotation == 1) tcanvasctx.drawImage(obj.canvas.canvas, -obj.canvas.canvas.width, 0);
+ if (obj.rotation == 2) tcanvasctx.drawImage(obj.canvas.canvas, -obj.canvas.canvas.width, -obj.canvas.canvas.height);
+ if (obj.rotation == 3) tcanvasctx.drawImage(obj.canvas.canvas, 0, -obj.canvas.canvas.height);
+
+ // Change the size and orientation and copy the canvas back into the rotation
+ if (obj.rotation == 0 || obj.rotation == 2) { obj.canvas.canvas.height = rw; obj.canvas.canvas.width = rh; }
+ if (obj.rotation == 1 || obj.rotation == 3) { obj.canvas.canvas.height = rh; obj.canvas.canvas.width = rw; }
+ obj.canvas.setTransform(1, 0, 0, 1, 0, 0);
+ obj.canvas.rotate((newrotation * 90) * Math.PI / 180);
+ obj.rotation = newrotation;
+ obj.canvas.drawImage(obj.tcanvas, _rotX(0, 0), _rotY(0, 0));
+
+ obj.width = obj.canvas.canvas.width;
+ obj.height = obj.canvas.canvas.height;
+ if (obj.onScreenResize != null) obj.onScreenResize(obj, obj.width, obj.height, obj.CanvasId);
+ return true;
+ }
+ // ###END###{DesktopRotation}
+
+ function _fixColor(c) { return (c > 127) ? (c + 32) : c; }
+
+ function _SendRefresh() {
+ // ###BEGIN###{DesktopInband}
+ if (obj.holding == true) return;
+ // ###END###{DesktopInband}
+ // ###BEGIN###{DesktopFocus}
+ if (obj.focusmode > 0) {
+ // Request only pixels around the last mouse position
+ var df = obj.focusmode * 2;
+ obj.Send(String.fromCharCode(3, 1) + ShortToStr(Math.max(Math.min(obj.ox, obj.mx) - obj.focusmode, 0)) + ShortToStr(Math.max(Math.min(obj.oy, obj.my) - obj.focusmode, 0)) + ShortToStr(df + Math.abs(obj.ox - obj.mx)) + ShortToStr(df + Math.abs(obj.oy - obj.my))); // FramebufferUpdateRequest
+ obj.ox = obj.mx;
+ obj.oy = obj.my;
+ } else {
+ // ###END###{DesktopFocus}
+ // Request the entire screen
+ obj.Send(String.fromCharCode(3, 1, 0, 0, 0, 0) + ShortToStr(obj.rwidth) + ShortToStr(obj.rheight)); // FramebufferUpdateRequest
+ // ###BEGIN###{DesktopFocus}
+ }
+ // ###END###{DesktopFocus}
+ }
+
+ obj.Start = function () {
+ //obj.Debug("KVM-Start");
+ obj.state = 0;
+ obj.acc = "";
+ obj.ZRLEfirst = 1;
+ //obj.inbytes = 0;
+ //obj.outbytes = 0;
+ // ###BEGIN###{Inflate}
+ obj.inflate.inflateReset();
+ // ###END###{Inflate}
+ // ###BEGIN###{DesktopInband}
+ obj.onKvmDataPending = [];
+ obj.onKvmDataAck = -1;
+ obj.kvmDataSupported = false;
+ // ###END###{DesktopInband}
+ for (var i in obj.sparecache) { delete obj.sparecache[i]; }
+ }
+
+ obj.Stop = function () {
+ obj.UnGrabMouseInput();
+ obj.UnGrabKeyInput();
+ if (obj.parent) { obj.parent.Stop(); }
+ }
+
+ obj.Send = function (x) {
+ //obj.Debug("KSend(" + x.length + "): " + rstr2hex(x));
+ //obj.outbytes += x.length;
+ if (obj.parent) { obj.parent.Send(x); }
+ }
+
+ var convertAmtKeyCodeTable = {
+ "Pause": 19,
+ "CapsLock": 20,
+ "Space": 32,
+ "Quote": 39,
+ "Minus": 45,
+ "NumpadMultiply": 42,
+ "NumpadAdd": 43,
+ "PrintScreen": 44,
+ "Comma": 44,
+ "NumpadSubtract": 45,
+ "NumpadDecimal": 46,
+ "Period": 46,
+ "Slash": 47,
+ "NumpadDivide": 47,
+ "Semicolon": 59,
+ "Equal": 61,
+ "OSLeft": 91,
+ "BracketLeft": 91,
+ "OSRight": 91,
+ "Backslash": 92,
+ "BracketRight": 93,
+ "ContextMenu": 93,
+ "Backquote": 96,
+ "NumLock": 144,
+ "ScrollLock": 145,
+ "Backspace": 0xff08,
+ "Tab": 0xff09,
+ "Enter": 0xff0d,
+ "NumpadEnter": 0xff0d,
+ "Escape": 0xff1b,
+ "Delete": 0xffff,
+ "Home": 0xff50,
+ "PageUp": 0xff55,
+ "PageDown": 0xff56,
+ "ArrowLeft": 0xff51,
+ "ArrowUp": 0xff52,
+ "ArrowRight": 0xff53,
+ "ArrowDown": 0xff54,
+ "End": 0xff57,
+ "Insert": 0xff63,
+ "F1": 0xffbe,
+ "F2": 0xffbf,
+ "F3": 0xffc0,
+ "F4": 0xffc1,
+ "F5": 0xffc2,
+ "F6": 0xffc3,
+ "F7": 0xffc4,
+ "F8": 0xffc5,
+ "F9": 0xffc6,
+ "F10": 0xffc7,
+ "F11": 0xffc8,
+ "F12": 0xffc9,
+ "ShiftLeft": 0xffe1,
+ "ShiftRight": 0xffe2,
+ "ControlLeft": 0xffe3,
+ "ControlRight": 0xffe4,
+ "AltLeft": 0xffe9,
+ "AltRight": 0xffea,
+ "MetaLeft": 0xffe7,
+ "MetaRight": 0xffe8
+ }
+ function convertAmtKeyCode(e) {
+ if (e.code.startsWith('Key') && e.code.length == 4) { return e.code.charCodeAt(3) + ((e.shiftKey == false) ? 32 : 0); }
+ if (e.code.startsWith('Digit') && e.code.length == 6) { return e.code.charCodeAt(5); }
+ if (e.code.startsWith('Numpad') && e.code.length == 7) { return e.code.charCodeAt(6); }
+ return convertAmtKeyCodeTable[e.code];
+ }
+
+ /*
+ Intel AMT only recognizes a small subset of keysym characters defined in the keysymdef.h so you don’t need to
+ implement all the languages (this is taken care by the USB Scancode Extension in RFB4.0 protocol).
+ The only subset recognized by the FW is the defined by the following sets : XK_LATIN1 , XK_MISCELLANY, XK_3270, XK_XKB_KEYS, XK_KATAKANA.
+ In addition to keysymdef.h symbols there are 6 japanese extra keys that we do support:
+
+ #define XK_Intel_EU_102kbd_backslash_pipe_45 0x17170056 // European 102-key: 45 (backslash/pipe), usb Usage: 0x64
+ #define XK_Intel_JP_106kbd_yen_pipe 0x1717007d // Japanese 106-key: 14 (Yen/pipe), usb Usage: 0x89
+ #define XK_Intel_JP_106kbd_backslash_underbar 0x17170073 // Japanese 106-key: 56 (backslash/underbar), usb Usage: 0x87
+ #define XK_Intel_JP_106kbd_NoConvert 0x1717007b // Japanese 106-key: 131 (NoConvert), usb Usage: 0x8b
+ #define XK_Intel_JP_106kbd_Convert 0x17170079 // Japanese 106-key: 132 (Convert), usb Usage: 0x8a
+ #define XK_Intel_JP_106kbd_Hirigana_Katakana 0x17170070 // Japanese 106-key: 133 (Hirigana/Katakana), usb Usage: 0x88
+ */
+
+ function _keyevent(d, e) {
+ if (!e) { e = window.event; }
+
+ if (e.code) {
+ // For new browsers, this mapping is keyboard language independent
+ var k = convertAmtKeyCode(e);
+ if (k != null) { obj.sendkey(k, d); }
+ } else {
+ var k = e.keyCode;
+ if (k == 173) k = 189; // '-' key (Firefox)
+ if (k == 61) k = 187; // '=' key (Firefox)
+ var kk = k;
+ if (e.shiftKey == false && k >= 65 && k <= 90) kk = k + 32;
+ if (k >= 112 && k <= 124) kk = k + 0xFF4E;
+ if (k == 8) kk = 0xff08; // Backspace
+ if (k == 9) kk = 0xff09; // Tab
+ if (k == 13) kk = 0xff0d; // Return
+ if (k == 16) kk = 0xffe1; // Shift (Left)
+ if (k == 17) kk = 0xffe3; // Ctrl (Left)
+ if (k == 18) kk = 0xffe9; // Alt (Left)
+ if (k == 27) kk = 0xff1b; // ESC
+ if (k == 33) kk = 0xff55; // PageUp
+ if (k == 34) kk = 0xff56; // PageDown
+ if (k == 35) kk = 0xff57; // End
+ if (k == 36) kk = 0xff50; // Home
+ if (k == 37) kk = 0xff51; // Left
+ if (k == 38) kk = 0xff52; // Up
+ if (k == 39) kk = 0xff53; // Right
+ if (k == 40) kk = 0xff54; // Down
+ if (k == 45) kk = 0xff63; // Insert
+ if (k == 46) kk = 0xffff; // Delete
+ if (k >= 96 && k <= 105) kk = k - 48; // Key pad numbers
+ if (k == 106) kk = 42; // Pad *
+ if (k == 107) kk = 43; // Pad +
+ if (k == 109) kk = 45; // Pad -
+ if (k == 110) kk = 46; // Pad .
+ if (k == 111) kk = 47; // Pad /
+ if (k == 186) kk = 59; // ;
+ if (k == 187) kk = 61; // =
+ if (k == 188) kk = 44; // ,
+ if (k == 189) kk = 45; // -
+ if (k == 190) kk = 46; // .
+ if (k == 191) kk = 47; // /
+ if (k == 192) kk = 96; // `
+ if (k == 219) kk = 91; // [
+ if (k == 220) kk = 92; // \
+ if (k == 221) kk = 93; // ]t
+ if (k == 222) kk = 39; // '
+ //console.log('Key' + d + ": " + k + " = " + kk);
+ obj.sendkey(kk, d);
+ }
+ return obj.haltEvent(e);
+ }
+
+ obj.sendkey = function (k, d) {
+ if (typeof k == 'object') { for (var i in k) { obj.sendkey(k[i][0], k[i][1]); } }
+ else { obj.Send(String.fromCharCode(4, d, 0, 0) + IntToStr(k)); }
+ }
+
+ function handleServerCutText(acc) {
+ if (acc.length < 8) return 0;
+ var len = ReadInt(obj.acc, 4) + 8;
+ if (acc.length < len) return 0;
+ // ###BEGIN###{DesktopInband}
+ if (obj.onKvmData != null) {
+ var d = acc.substring(8, len);
+ if ((d.length >= 16) && (d.substring(0, 15) == '\0KvmDataChannel')) {
+ if (obj.kvmDataSupported == false) { obj.kvmDataSupported = true; console.log('KVM Data Channel Supported.'); }
+ if (((obj.onKvmDataAck == -1) && (d.length == 16)) || (d.charCodeAt(15) != 0)) { obj.onKvmDataAck = true; }
+ if (urlvars && urlvars['kvmdatatrace']) { console.log('KVM-Recv(' + (d.length - 16) + '): ' + d.substring(16)); }
+ if (d.length > 16) { obj.onKvmData(d.substring(16)); } // Event the data and ack
+ if ((obj.onKvmDataAck == true) && (obj.onKvmDataPending.length > 0)) { obj.sendKvmData(obj.onKvmDataPending.shift()); } // Send pending data
+ }
+ }
+ // ###END###{DesktopInband}
+ return len;
+ }
+
+ // ###BEGIN###{DesktopInband}
+ obj.sendKvmData = function (x) {
+ if (obj.onKvmDataAck !== true) {
+ obj.onKvmDataPending.push(x);
+ } else {
+ if (urlvars && urlvars['kvmdatatrace']) { console.log('KVM-Send(' + x.length + '): ' + x); }
+ x = '\0KvmDataChannel\0' + x;
+ obj.Send(String.fromCharCode(6, 0, 0, 0) + IntToStr(x.length) + x);
+ obj.onKvmDataAck = false;
+ }
+ }
+
+ // Send a HWKVM keep alive if it's not been sent in the last 5 seconds.
+ obj.sendKeepAlive = function () {
+ if (obj.lastKeepAlive < Date.now() - 5000) { obj.lastKeepAlive = Date.now(); obj.Send(String.fromCharCode(6, 0, 0, 0) + IntToStr(16) + '\0KvmDataChannel\0'); }
+ }
+ // ###END###{DesktopInband}
+
+ obj.SendCtrlAltDelMsg = function () { obj.sendcad(); }
+ obj.sendcad = function () {
+ obj.sendkey(0xFFE3, 1); // Control
+ obj.sendkey(0xFFE9, 1); // Alt
+ obj.sendkey(0xFFFF, 1); // Delete
+ obj.sendkey(0xFFFF, 0); // Delete
+ obj.sendkey(0xFFE9, 0); // Alt
+ obj.sendkey(0xFFE3, 0); // Control
+ }
+
+ var _MouseInputGrab = false;
+ var _KeyInputGrab = false;
+
+ obj.GrabMouseInput = function () {
+ if (_MouseInputGrab == true) return;
+ var c = obj.canvas.canvas;
+ c.onmouseup = obj.mouseup;
+ c.onmousedown = obj.mousedown;
+ c.onmousemove = obj.mousemove;
+ //if (navigator.userAgent.match(/mozilla/i)) c.DOMMouseScroll = obj.xxDOMMouseScroll; else c.onmousewheel = obj.xxMouseWheel;
+ _MouseInputGrab = true;
+ }
+
+ obj.UnGrabMouseInput = function () {
+ if (_MouseInputGrab == false) return;
+ var c = obj.canvas.canvas;
+ c.onmousemove = null;
+ c.onmouseup = null;
+ c.onmousedown = null;
+ //if (navigator.userAgent.match(/mozilla/i)) c.DOMMouseScroll = null; else c.onmousewheel = null;
+ _MouseInputGrab = false;
+ }
+
+ obj.GrabKeyInput = function () {
+ if (_KeyInputGrab == true) return;
+ document.onkeyup = obj.handleKeyUp;
+ document.onkeydown = obj.handleKeyDown;
+ document.onkeypress = obj.handleKeys;
+ _KeyInputGrab = true;
+ }
+
+ obj.UnGrabKeyInput = function () {
+ if (_KeyInputGrab == false) return;
+ document.onkeyup = null;
+ document.onkeydown = null;
+ document.onkeypress = null;
+ _KeyInputGrab = false;
+ }
+
+ obj.handleKeys = function (e) { return obj.haltEvent(e); }
+ obj.handleKeyUp = function (e) { return _keyevent(0, e); }
+ obj.handleKeyDown = function (e) { return _keyevent(1, e); }
+ obj.haltEvent = function (e) { if (e.preventDefault) e.preventDefault(); if (e.stopPropagation) e.stopPropagation(); return false; }
+
+ // RFB "PointerEvent" and mouse handlers
+ obj.mousedown = function (e) { obj.buttonmask |= (1 << e.button); return obj.mousemove(e, 1); }
+ obj.mouseup = function (e) { obj.buttonmask &= (0xFFFF - (1 << e.button)); return obj.mousemove(e, 1); }
+ obj.mousemove = function (e, force) {
+ if (obj.state < 4) return true;
+ var pos = obj.getPositionOfControl(Q(obj.canvasid));
+ obj.mx = (e.pageX - pos[0]) * (obj.canvas.canvas.height / Q(obj.canvasid).offsetHeight);
+ obj.my = ((e.pageY - pos[1] + (scrolldiv ? scrolldiv.scrollTop : 0)) * (obj.canvas.canvas.width / Q(obj.canvasid).offsetWidth));
+
+ // ###BEGIN###{DesktopRotation}
+ if (obj.noMouseRotate != true) {
+ obj.mx2 = _crotX(obj.mx, obj.my);
+ obj.my = _crotY(obj.mx, obj.my);
+ obj.mx = obj.mx2;
+ }
+ // ###END###{DesktopRotation}
+
+ // This is the mouse motion nagle timer. Slow down the mouse motion event rate.
+ if (force == 1) {
+ obj.Send(String.fromCharCode(5, obj.buttonmask) + ShortToStr(obj.mx) + ShortToStr(obj.my));
+ if (obj.mNagleTimer != null) { clearTimeout(obj.mNagleTimer); obj.mNagleTimer = null; }
+ } else {
+ if (obj.mNagleTimer == null) {
+ obj.mNagleTimer = setTimeout(function () {
+ obj.Send(String.fromCharCode(5, obj.buttonmask) + ShortToStr(obj.mx) + ShortToStr(obj.my));
+ obj.mNagleTimer = null;
+ }, 50);
+ }
+ }
+
+ // ###BEGIN###{DesktopFocus}
+ // Update focus area if we are in focus mode
+ QV('DeskFocus', obj.focusmode);
+ if (obj.focusmode != 0) {
+ var x = Math.min(obj.mx, obj.canvas.canvas.width - obj.focusmode),
+ y = Math.min(obj.my, obj.canvas.canvas.height - obj.focusmode),
+ df = obj.focusmode * 2,
+ c = Q(obj.canvasid),
+ qx = c.offsetHeight / obj.canvas.canvas.height,
+ qy = c.offsetWidth / obj.canvas.canvas.width,
+ q = QS('DeskFocus'),
+ ppos = obj.getPositionOfControl(Q(obj.canvasid).parentElement);
+ q.left = (Math.max(((x - obj.focusmode) * qx), 0) + (pos[0] - ppos[0])) + 'px';
+ q.top = (Math.max(((y - obj.focusmode) * qy), 0) + (pos[1] - ppos[1])) + 'px';
+ q.width = ((df * qx) - 6) + 'px';
+ q.height = ((df * qx) - 6) + 'px';
+ }
+ // ###END###{DesktopFocus}
+
+ return obj.haltEvent(e);
+ }
+
+ obj.getPositionOfControl = function (Control) {
+ var Position = Array(2);
+ Position[0] = Position[1] = 0;
+ while (Control) {
+ Position[0] += Control.offsetLeft;
+ Position[1] += Control.offsetTop;
+ Control = Control.offsetParent;
+ }
+ return Position;
+ }
+
+ return obj;
+}
diff --git a/amt-ider-node-0.0.1.js b/amt-ider-node-0.0.1.js
new file mode 100644
index 0000000..ac72f0a
--- /dev/null
+++ b/amt-ider-node-0.0.1.js
@@ -0,0 +1,509 @@
+/**
+* @description Meshcentral
+* @author Ylian Saint-Hilaire
+* @version v0.0.1
+*/
+
+function CreateIMRSDKWrapper() {
+ var obj = {};
+
+ var _IMRSDK;
+ var _ImrSdkVersion;
+ var _ref = require("ref");
+ var _ffi = require("ffi");
+ var _struct = require('ref-struct');
+ var _arrayType = require('ref-array');
+ obj.pendingData = {};
+
+ // Callback from the native lib back into js (StdCall)
+ var uintPtr = _ref.refType('uint');
+ var OpenHandlerCallBack = _ffi.Callback('int', ['uint', 'uint'], _ffi.FFI_STDCALL, function (clientID, conID) { obj.pendingData[conID] = ''; return 0; });
+ var CloseHandlerCallBack = _ffi.Callback('int', ['uint'], _ffi.FFI_STDCALL, function (conID) { obj.pendingData[conID] = ''; return 0; });
+ var ReceiveHandlerCallBack = _ffi.Callback('int', ['pointer', uintPtr, 'uint'], _ffi.FFI_STDCALL, function (bufferPtr, lengthPtr, conID) {
+ try {
+ var bufferLen = lengthPtr.readUInt32LE(0), buffer = _ref.reinterpret(bufferPtr, bufferLen);
+ lengthPtr.writeUInt32LE(obj.pendingData[conID].length, 0);
+ for (var i = 0; i < obj.pendingData[conID].length; i++) { buffer[i] = obj.pendingData[conID].charCodeAt(i); }
+ //console.log("ReceiveHandlerCallBack(conID: " + conID + ", Len: " + obj.pendingData[conID].length + ")");
+ obj.pendingData[conID] = '';
+ } catch (e) { console.log(e); }
+ return 0;
+ });
+ var SendHandlerCallBack = _ffi.Callback('int', ['pointer', 'uint', 'uint'], _ffi.FFI_STDCALL, function (ptr, length, conID) {
+ try {
+ var buffer = _ref.reinterpret(ptr, length), str = '';
+ for (var i = 0; i < length; i++) { str += String.fromCharCode(buffer[i]); }
+ //console.log("SendHandlerCallBack(conID: " + conID + ", Len: " + length + ")");
+ obj.client.write(str, 'binary');
+ } catch (e) { console.log(e); }
+ return 0;
+ });
+
+ var _IMRVersion = _struct({ 'major': 'ushort', 'minor': 'ushort' });
+ var _IMRVersionPtr = _ref.refType(_IMRVersion);
+ var _IMRClientInfo = _struct({ 'type': 'int', 'ip': _arrayType('char', 128), 'guid': _arrayType('char', 16)});
+ var _IMRClientInfoPtr = _ref.refType(_IMRClientInfo);
+ var _ProxySettings = _struct({ 'type': 'int', 'server': _arrayType('char', 128), 'port': 'int', 'user': _arrayType('char', 128), 'pass': _arrayType('char', 128) });
+ var _TCPSessionParams = _struct({ 'user': _arrayType('char', 128), 'pass': _arrayType('char', 128) });
+ var _TCPSessionParamsPtr = _ref.refType(_TCPSessionParams);
+ var _TCPSessionParamsEx = _struct({ 'version': 'int', 'user': _arrayType('char', 128), 'pass': _arrayType('char', 128), 'proxy': _ProxySettings });
+ var _TCPSessionParamsExPtr = _ref.refType(_TCPSessionParamsEx);
+ var _TCPSessionParamsEx2 = _struct({ 'version': 'int', 'user': _arrayType('char', 128), 'pass': _arrayType('char', 128), 'domain': _arrayType('char', 254), 'proxy': _ProxySettings });
+ var _TCPSessionParamsEx2Ptr = _ref.refType(_TCPSessionParamsEx2);
+ var _FeaturesSupported = _struct({ 'ider_dev_pri': 'int', 'ider_dev_sec': 'int', 'reserved': _arrayType('char', 30) });
+ var _FeaturesSupportedPtr = _ref.refType(_FeaturesSupported);
+ var _IDERTout = _struct({ 'rx_timeout': 'ushort', 'tx_timeout': 'ushort', 'hb_timeout': 'ushort' });
+ var _IDERToutPtr = _ref.refType(_IDERTout);
+ var _IDERStatistics = _struct({
+ 'error_state': 'int',
+ 'data_transfer': 'int',
+ 'num_reopen': 'ushort',
+ 'num_error': 'int',
+ 'num_reset': 'int',
+ 'last_cmd_length': 'int',
+ 'data_sent': 'int',
+ 'data_received': 'int',
+ 'packets_sent': 'int',
+ 'packets_received': 'int'
+ });
+ var _IDERStatisticsPtr = _ref.refType(_IDERStatistics);
+ var _IDERDeviceState = _struct({ 'pri_default': 'int', 'pri_current': 'int', 'sec_default': 'int', 'sec_current': 'int' });
+ var _IDERDeviceStatePtr = _ref.refType(_IDERDeviceState);
+ var _IDERDeviceCmd = _struct({ 'pri_op': 'int', 'pri_timing': 'int', 'sec_op': 'int', 'sec_timing': 'int' });
+ var _IDERDeviceCmdPtr = _ref.refType(_IDERDeviceCmd);
+ var _IDERDeviceResult = _struct({ 'pri_res': 'int', 'sec_res': 'int' });
+ var _IDERDeviceResultPtr = _ref.refType(_IDERDeviceResult);
+ var _SockCallBacks = _struct({ 'OpenHandler': 'pointer', 'CloseHandler': 'pointer', 'ReceiveHandler': 'pointer', 'SendHandler': 'pointer' });
+ var _SockCallBacksPtr = _ref.refType(_SockCallBacks);
+ var _intPtr = _ref.refType('int');
+
+ function _Setup(lib) {
+ try {
+ _IMRSDK = _ffi.Library(lib, {
+ "IMR_Init": ['uint', [_IMRVersionPtr, 'string']], // IMRResult IMR_Init(IMRVersion *version, char *ini_file);
+ "IMR_InitEx": ['uint', [_IMRVersionPtr, 'string', _SockCallBacksPtr]], // IMRResult IMR_Init(IMRVersion *version, char *ini_file, void *funcPtrs);
+ "IMR_ReadyReadSock": ['uint', ['uint']], // IMRResult IMR_ReadyReadSock(uint conid);
+ "IMR_Close": ['uint', []], // IMRResult IMR_Close();
+ "IMR_GetErrorStringLen": ['uint', ['uint', _intPtr]], // IMRResult IMR_GetErrorStringLen(IMRResult, int * str_len);
+ "IMR_GetErrorString": ['uint', ['uint', 'pointer']], // IMRResult IMR_GetErrorString(IMRResult, char * str);
+ "IMR_SetCertificateInfo": ['uint', ['string', 'string', 'string']], // IMRResult IMR_SetCertificateInfo(const char *root_cert, const char *private_cert, const char *cert_pass);
+ "IMR_SetClientCertificate": ['uint', ['string']], // IMRResult IMR_SetClientCertificate(const char *common_name);
+ "IMR_AddClient": ['uint', ['int', 'string', 'pointer', _intPtr]], // IMRResult IMR_AddClient(ClientType new_client_type, char * client_ip, GUIDType client_guid, ClientID * new_client_id);
+ "IMR_RemoveClient": ['uint', ['int']], // IMRResult IMR_RemoveClient(ClientID client_id);
+ "IMR_RemoveAllClients": ['uint', []], // IMRResult IMR_RemoveAllClients();
+ "IMR_GetAllClients": ['uint', [_arrayType('int'), _intPtr]], // IMRResult IMR_GetAllClients(ClientID * client_list, int * client_list_size);
+ "IMR_GetClientInfo": ['uint', ['int', _IMRClientInfoPtr]], // IMRResult IMR_GetClientInfo(ClientID client_id, ClientInfo *);
+ "IMR_IDEROpenTCPSession": ['uint', ['int', _TCPSessionParamsPtr, _IDERToutPtr, 'string', 'string']], // IMRResult IMR_IDEROpenTCPSession(ClientID client_id, TCPSessionParams * params, IDERTout * touts, char * drive0, char * drive1);
+ "IMR_IDEROpenTCPSessionEx": ['uint', ['int', _TCPSessionParamsExPtr, _IDERToutPtr, 'string', 'string']], // IMRResult IMR_IDEROpenTCPSessionEx(ClientID client_id, TCPSessionParamsEx * params, IDERTout * touts, char * drive0, char * drive1);
+ "IMR_IDEROpenTCPSessionEx2": ['uint', ['int', _TCPSessionParamsEx2Ptr, _IDERToutPtr, 'string', 'string']], // IMRResult IMR_IDEROpenTCPSessionEx2(ClientID client_id, TCPSessionParamsEx2 * params, IDERTout * touts, char * drive0, char * drive1);
+ "IMR_IDERCloseSession": ['uint', ['int']], // IMRResult IMR_IDERCloseSession(ClientID client_id);
+ "IMR_IDERClientFeatureSupported" : ['uint', ['int', _FeaturesSupportedPtr]], // IMRResult IMR_IDERClientFeatureSupported(ClientID client_id, FeaturesSupported * supported);
+ "IMR_IDERGetDeviceState" : ['uint', ['int', _IDERDeviceStatePtr]], // IMRResult IMR_IDERGetDeviceState(ClientID client_id, IDERDeviceState * state);
+ "IMR_IDERSetDeviceState" : ['uint', ['int', _IDERDeviceCmdPtr, _IDERDeviceResultPtr]], // IMRResult IMR_IDERSetDeviceState(ClientID client_id, IDERDeviceCmd * cmd, IDERDeviceResult * result);
+ "IMR_IDERGetSessionStatistics": ['uint', ['int', _IDERStatisticsPtr]], // IMRResult IMR_IDERGetSessionStatistics(ClientID client_id, IDERStatistics * stat);
+ "IMR_SetOpt": ['uint', ['int', 'string', 'string', 'int']], // IMRResult IMR_SetOpt(/*IN*/ClientID id, /*IN*/int optname, /*IN*/ const char *optval, /*IN*/ int optlen);
+ "IMR_GetOpt": ['uint', ['int', 'string', 'pointer', _intPtr]], // IMRResult IMR_GetOpt(/*IN*/ClientID id, /*IN*/int optname, /*OUT*/ char *optval, /*OUT*/ int* optlen);
+ });
+ } catch (e) { return false; }
+ return true;
+ }
+
+ // Try to link to both 32bit and 64bit IMRSDK.dll's
+ if (_Setup('imrsdk') == false) { if (_Setup('imrsdk_x64') == false) { return null; } }
+
+ // IMR_Init
+ obj.Init = function() {
+ var version = new _IMRVersion();
+ var error = _IMRSDK.IMR_Init(version.ref(), "imrsdk.ini");
+ if (error == 4) return _ImrSdkVersion; // If already initialized, return previous version information.
+ if (error != 0) { throw obj.GetErrorString(error); }
+ _ImrSdkVersion = { major: version.major, minor: version.minor };
+ return _ImrSdkVersion;
+ }
+
+ // IMR_InitEx
+ obj.InitEx = function(client) {
+ var version = new _IMRVersion();
+ var callbacks = new _SockCallBacks();
+ callbacks.OpenHandler = OpenHandlerCallBack;
+ callbacks.CloseHandler = CloseHandlerCallBack;
+ callbacks.ReceiveHandler = ReceiveHandlerCallBack;
+ callbacks.SendHandler = SendHandlerCallBack;
+ obj.client = client;
+
+ var error = _IMRSDK.IMR_InitEx(version.ref(), "imrsdk.ini", callbacks.ref());
+ if (error == 4) return _ImrSdkVersion; // If already initialized, return previous version information.
+ if (error != 0) { throw obj.GetErrorString(error); }
+ _ImrSdkVersion = { major: version.major, minor: version.minor };
+ return _ImrSdkVersion;
+ }
+
+ // IMR_ReadyReadSock
+ obj.ReadyReadSock = function (connid, func) { _IMRSDK.IMR_ReadyReadSock.async(connid, func); }
+
+ // IMR_Close
+ obj.Close = function (func) { _IMRSDK.IMR_Close.async(func); }
+
+ // IMR_GetErrorString
+ obj.GetErrorString = function (v) {
+ var errorStringLen = _ref.alloc('int');
+ var error = _IMRSDK.IMR_GetErrorStringLen(v, errorStringLen); if (error != 0) return 'Unknown IMRSDK Error ' + v;
+ var errorStringLenEx = errorStringLen.deref();
+ var errorString = new Buffer(errorStringLenEx);
+ error = _IMRSDK.IMR_GetErrorString(v, errorString); if (error != 0) return 'Unknown IMRSDK Error ' + v;
+ //console.log('IMRSDK ' + errorString.toString().substring(0, errorStringLenEx));
+ return 'IMRSDK ' + errorString.toString().substring(0, errorStringLenEx);
+ }
+
+ // IMR_SetCertificateInfo
+ obj.SetCertificateInfo = function (root_cert, private_cert, cert_pass) {
+ var error = _IMRSDK.IMR_SetCertificateInfo(root_cert, private_cert, cert_pass); if (error != 0) { throw obj.GetErrorString(error); }
+ }
+
+ // IMR_SetClientCertificate
+ obj.SetClientCertificate = function (common_name) {
+ var error = _IMRSDK.IMR_SetClientCertificate(common_name); if (error != 0) { throw obj.GetErrorString(error); }
+ }
+
+ // IMR_AddClient
+ // Type: 1=TCP, 2=TLS
+ obj.AddClient = function (type, ip) {
+ var guid = new Buffer(16);
+ for (var i = 0; i < 16; i++) { guid[i] = Math.floor(Math.random() * 255); }
+ var clientid = _ref.alloc('int');
+ var error = _IMRSDK.IMR_AddClient(type, ip, guid, clientid); if (error != 0) { throw obj.GetErrorString(error); }
+ return clientid.deref();
+ }
+
+ // IMR_RemoveClient
+ obj.RemoveClient = function (client_id) {
+ var error = _IMRSDK.IMR_RemoveClient(client_id); if (error != 0) { throw obj.GetErrorString(error); }
+ }
+
+ // IMR_RemoveAllClients
+ obj.RemoveAllClients = function () {
+ var error = _IMRSDK.IMR_RemoveAllClients(); if (error != 0) { throw obj.GetErrorString(error); }
+ }
+
+ // IMR_GetAllClients
+ obj.GetAllClients = function () {
+ var clientListLength = _ref.alloc('int');
+ var error = _IMRSDK.IMR_GetAllClients(null, clientListLength); if (error != 0) { throw obj.GetErrorString(error); }
+ var clientListLengthEx = clientListLength.deref();
+ var IntArray = _arrayType(_ref.types.int)
+ var buf = new Buffer(4 * clientListLengthEx);
+ var error = _IMRSDK.IMR_GetAllClients(buf, clientListLength); if (error != 0) { throw obj.GetErrorString(error); }
+ clientListLengthEx = clientListLength.deref();
+ var array = IntArray.untilZeros(buf)
+ var clientids = [];
+ for (var i = 0; i < clientListLengthEx; i++) { clientids.push(array[i]); }
+ return clientids;
+ }
+
+ // IMR_GetClientInfo
+ obj.GetClientInfo = function (client_id) {
+ var client = new obj.IMRClientInfo();
+ var error = _IMRSDK.IMR_GetClientInfo(client_id, client.ref()); if (error != 0) { throw obj.GetErrorString(error); }
+ var ip = '', i = 0;
+ while (client.ip[i] != 0) { ip += String.fromCharCode(client.ip[i++]); }
+ return { type: client.type, ip: ip };
+ }
+
+ // IMR_IDEROpenTCPSession
+ obj.IDEROpenTCPSessionAsync = function (client_id, user, pass, driveimg, driveiso, func) {
+ //console.log('IDEROpenTCPSessionAsync', client_id, user, pass, driveimg, driveiso);
+ // Setup parameters
+ var params = new _TCPSessionParams();
+ var user2 = obj.decode_utf8(user);
+ var pass2 = obj.decode_utf8(pass);
+ for (var i = 0; i < 128; i++) { params.user[i] = 0; }
+ for (var i = 0; i < user2.length; i++) { params.user[i] = user2.charCodeAt(i); }
+ for (var i = 0; i < 128; i++) { params.pass[i] = 0; }
+ for (var i = 0; i < pass2.length; i++) { params.pass[i] = pass2.charCodeAt(i); }
+
+ // Setup
+ var IDERTout = new _IDERTout();
+ IDERTout.rx_timeout = 30000; // Default is 10000
+ IDERTout.tx_timeout = 0; // Default is 0
+ IDERTout.hb_timeout = 20000; // Default is 5000
+
+ // Make the call
+ _IMRSDK.IMR_IDEROpenTCPSession.async(client_id, params.ref(), IDERTout.ref(), driveimg, driveiso, function (x, error) {
+ if (error == 38) { return error; } // User consent required
+ //if (error != 0) { throw obj.GetErrorString(error); }
+ if (func != null) { func(error); }
+ });
+ }
+
+ // IMR_IDERCloseSession
+ obj.IDERCloseSessionAsync = function (client_id, func) { _IMRSDK.IMR_IDERCloseSession.async(client_id, func); }
+
+ // IMR_IDERClientFeatureSupported
+ obj.IDERClientFeatureSupported = function (client_id) {
+ var features = new _FeaturesSupported();
+ var error = _IMRSDK.IMR_IDERClientFeatureSupported(client_id, features.ref()); if (error != 0) { throw obj.GetErrorString(error); }
+ return { ider_dev_pri: features.ider_dev_pri, ider_dev_sec: features.ider_dev_sec }
+ }
+
+ // IMR_IDERGetDeviceState
+ obj.IDERGetDeviceState = function (client_id) {
+ var state = new _IDERDeviceState();
+ var error = _IMRSDK.IMR_IDERGetDeviceState(client_id, state.ref()); if (error != 0) { throw obj.GetErrorString(error); }
+ return { pri_default: state.pri_default, pri_current: state.pri_current, sec_default: state.sec_default, sec_current: state.sec_current }
+ }
+
+ // IMR_IDERSetDeviceState Async
+ obj.IDERSetDeviceStateAsync = function (client_id, pri_op, pri_timing, sec_op, sec_timing, func) {
+ var cmd = new _IDERDeviceCmd();
+ cmd.pri_op = pri_op;
+ cmd.pri_timing = pri_timing;
+ cmd.sec_op = sec_op;
+ cmd.sec_timing = sec_timing;
+ var result = new _IDERDeviceResult();
+ _IMRSDK.IMR_IDERSetDeviceState.async(client_id, cmd.ref(), result.ref(), function (x, error) {
+ if (func != null) func(error, { pri_res: result.pri_res, sec_res: result.sec_res });
+ });
+ }
+
+ // IMR_IDERGetSessionStatistics
+ obj.IDERGetSessionStatistics = function (client_id) {
+ var stats = new _IDERStatistics();
+ var error = _IMRSDK.IMR_IDERGetSessionStatistics(client_id, stats.ref()); if (error != 0) { throw obj.GetErrorString(error); }
+ return { error_state: stats.error_state, data_transfer: stats.data_transfer, num_reopen: stats.num_reopen, num_error: stats.num_error, num_reset: stats.num_reset, last_cmd_length: stats.last_cmd_length, data_sent: stats.data_sent, data_received: stats.data_received, packets_sent: stats.packets_sent, packets_received: stats.packets_received };
+ }
+
+ // IMR_SetOpt
+ obj.SetOpt = function (client_id, optname, optval) {
+ var error = _IMRSDK.IMR_SetOpt(client_id, optname, optval, optval.length); if (error != 0) { throw obj.GetErrorString(error); }
+ }
+
+ // IMR_GetOpt
+ obj.GetOpt = function (client_id, optname) {
+ var len = _ref.alloc('int');
+ var error = _IMRSDK.IMR_GetOpt(client_id, optname, null, len); if (error != 0) { throw obj.GetErrorString(error); }
+ var buf = new Buffer(len.deref() + 1);
+ var error = _IMRSDK.IMR_GetOpt(client_id, optname, buf, len); if (error != 0) { throw obj.GetErrorString(error); }
+ // console.log(buf);
+ return buf; // TODO: Return something correct after testing this call
+ }
+
+ // UTF-8 encoding & decoding functions
+ obj.encode_utf8 = function (s) { return unescape(encodeURIComponent(s)); }
+ obj.decode_utf8 = function (s) { return decodeURIComponent(escape(s)); }
+
+ return obj;
+}
+
+globalIderPendingCalls = 0;
+
+// Construct a Intel AMT IDER object
+var CreateAmtRemoteIderIMR = function () {
+ if (globalIderPendingCalls != 0) { console.log('Incomplete IDER cleanup (' + globalIderPendingCalls + ').'); return null; } // IDER is not ready.
+ var _net = require('net');
+ var _tls = require('tls');
+
+ var obj = {};
+ obj.onStateChanged = null;
+ obj.state = 0;
+
+ obj.m = {};
+ obj.m.protocol = 3; // IDER
+ obj.m.state = 0;
+ obj.m.bytesToAmt = 0;
+ obj.m.bytesFromAmt = 0;
+ obj.m.imrsdk = null;
+ obj.receivedCount = 0;
+
+ // Private method
+ obj.StateChange = function (newstate) { if (obj.state != newstate) { obj.state = newstate; obj.onStateChanged(obj, obj.state); } }
+
+ obj.m.Start = function (host, port, user, pass, tls, wsmanCert, tlsOptions) {
+ obj.constants = require('constants');
+ obj.m.host = host;
+ obj.m.port = port;
+ obj.m.user = user;
+ obj.m.pass = pass;
+ obj.m.tls = tls;
+ obj.m.xtlsoptions = tlsOptions;
+ obj.m.wsmanCert = wsmanCert;
+ obj.m.bytesToAmt = 0;
+ obj.m.bytesFromAmt = 0;
+
+ if (obj.m.onDialogPrompt) {
+ if (require('os').platform() == 'win32') {
+ obj.m.onDialogPrompt(obj.m, { 'html': '
Select a CDROM and Floppy disk image to start the disk redirection.
Source
Start
' });
+ } else {
+ obj.m.onDialogPrompt(obj.m, { 'html': '
Select a CDROM and Floppy disk image to start the disk redirection.
Start
' });
+ }
+ }
+ }
+
+ obj.m.Stop = function () {
+ if (obj.m.client != null) {
+ //console.log('obj.m.Stop - client');
+ try { obj.m.client.destroy(); } catch (e) { console.log(e); }
+ delete obj.m.client;
+ }
+ if (obj.m.imrsdk) {
+ //console.log('obj.m.Stop - imrsdk', obj.m.clientid);
+ try
+ {
+ if (obj.m.clientid !== undefined) {
+ try { obj.m.imrsdk.IDERCloseSessionAsync(obj.m.clientid, function (error) { }); } catch (e) { }
+ delete obj.m.clientid;
+ }
+ obj.m.imrsdk.Close(function (error) { });
+ } catch (e) { }
+ delete obj.m.imrsdk;
+ }
+ obj.StateChange(0);
+ }
+
+ obj.m.Update = function () {
+ if ((obj.m.imrsdk != undefined) && (obj.m.clientid !== undefined)) {
+ try {
+ var stats = obj.m.imrsdk.IDERGetSessionStatistics(obj.m.clientid);
+ obj.m.bytesToAmt = stats.data_sent;
+ obj.m.bytesFromAmt = stats.data_received;
+ } catch (e) {
+ obj.m.bytesToAmt = -1;
+ obj.m.bytesFromAmt = -1;
+ }
+ } else {
+ obj.m.bytesToAmt = 0;
+ obj.m.bytesFromAmt = 0;
+ }
+ }
+
+ obj.m.dialogPrompt = function (userConsentFunc) {
+ try {
+ obj.m.Stop();
+ if (Q('storageserveroption')) {
+ var sel = 0;
+ if (require('os').platform() == 'win32') { sel = Q('storagesourceoption').value; }
+ if ((sel & 1) == 0) {
+ var x = Q('iderisofile');
+ if (!x || x.files.length != 1) { obj.m.isopath = 'empty.iso'; } else { obj.m.isopath = x.files[0].path; }
+ } else {
+ obj.m.isopath = Q('iderisodrive').value;
+ }
+ if ((sel & 2) == 0) {
+ var x = Q('iderimgfile');
+ if (!x || x.files.length != 1) { obj.m.imgpath = 'empty.img'; } else { obj.m.imgpath = x.files[0].path; }
+ } else {
+ obj.m.imgpath = Q('iderimgdrive').value;
+ }
+ obj.m.startoption = Q('storageserveroption').value;
+ startIderSession(userConsentFunc);
+ }
+ } catch (e) {
+ //console.log(e);
+ obj.m.onDialogPrompt(obj.m, { 'html': e }, 1);
+ }
+ }
+
+ function startIderSession(userConsentFunc) {
+ if (globalIderPendingCalls != 0) { console.log('Incomplete IDER cleanup (' + globalIderPendingCalls + ').'); return; }
+ try {
+ //console.log("IDER-Start");
+ if (obj.m.xtlsoptions && obj.m.xtlsoptions.meshServerConnect) {
+ // Open thru MeshCentral websocket wrapper
+ obj.m.client = CreateWebSocketWrapper(obj.m.xtlsoptions.host, obj.m.xtlsoptions.port, '/webrelay.ashx?user=' + encodeURIComponent(obj.m.xtlsoptions.username) + '&pass=' + encodeURIComponent(obj.m.xtlsoptions.password) + '&host=' + encodeURIComponent(obj.m.host) + '&p=2', obj.m.xtlsoptions.xtlsFingerprint);
+ obj.m.client.connect(function () {
+ //console.log('IDER Connected WS, ' + obj.m.xtlsoptions.host + ':' + obj.m.xtlsoptions.port + ' to ' + obj.m.host);
+ startIderSessionEx(userConsentFunc);
+ });
+ } else if (obj.m.tls == 0) {
+ // Open connection without TLS
+ obj.m.client = new _net.Socket();
+ obj.m.client.connect(obj.m.port, obj.m.host, function () {
+ //console.log('IDER Connected TCP, ' + obj.m.host + ':' + obj.m.port);
+ startIderSessionEx(userConsentFunc);
+ });
+ } else {
+ // Open connection with TLS
+ if (obj.m.xtlsoptions == null) { obj.m.xtlsoptions = { secureProtocol: 'TLSv1_method', ciphers: 'RSA+AES:!aNULL:!MD5:!DSS', secureOptions: obj.constants.SSL_OP_NO_SSLv2 | obj.constants.SSL_OP_NO_SSLv3 | obj.constants.SSL_OP_NO_COMPRESSION | obj.constants.SSL_OP_CIPHER_SERVER_PREFERENCE, rejectUnauthorized: false }; }
+ obj.m.client = _tls.connect(obj.m.port, obj.m.host, obj.m.xtlsoptions, function () {
+ //console.log('IDER Connected TLS, ' + obj.m.host + ':' + obj.m.port);
+
+ // Check the Intel AMT certificate, it must be the same as the one used for WSMAN. If not, disconnect.
+ var iderTlsCertificate = obj.m.client.getPeerCertificate();
+ if ((iderTlsCertificate == null) || (obj.m.wsmanCert == null) || (iderTlsCertificate.fingerprint != obj.m.wsmanCert.fingerprint)) {
+ console.log("Invalid IDER certificate, disconnecting.", iderTlsCertificate);
+ obj.m.Stop();
+ } else {
+ startIderSessionEx(userConsentFunc)
+ }
+ });
+ }
+
+ obj.m.client.setEncoding('binary');
+
+ obj.m.client.on('data', function (data) {
+ //console.log("IDER-RECV(" + data.length + ", " + obj.receivedCount + "): " + rstr2hex(data));
+
+ if (obj.m.imrsdk == null) { return; }
+
+ if ((obj.receivedCount == 0) && (data.charCodeAt(0) == 0x11) && (data.charCodeAt(1) == 0x05)) {
+ // We got a user consent error, handle it now before IMRSDK.dll can get it.
+ console.log('IDER user consent required.');
+ obj.m.imrsdk.pendingData[obj.m.clientid] = String.fromCharCode(0x11, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); // Try to cause a fault.
+ obj.m.imrsdk.ReadyReadSock(0, function (x, error) { });
+ setTimeout(function () { obj.m.userConsentFunc(startIderSession); }, 500);
+ } else {
+ if (obj.m.imrsdk.pendingData[obj.m.clientid] == null) { obj.m.imrsdk.pendingData[obj.m.clientid] = data; } else { obj.m.imrsdk.pendingData[obj.m.clientid] += data; }
+ obj.m.imrsdk.ReadyReadSock(0, function (x, error) { });
+ }
+ obj.receivedCount += data.length;
+ });
+
+ obj.m.client.on('close', function () { obj.m.Stop(); });
+
+ // If the TCP connection causes an error, disconnect the associated web socket.
+ obj.m.client.on('error', function (err) { obj.m.Stop(); });
+ } catch (e) {
+ //console.log(e);
+ obj.m.Stop();
+ obj.m.onDialogPrompt(obj.m, { 'html': e }, 1);
+ }
+ }
+
+ function startIderSessionEx(userConsentFunc) {
+ try {
+ //console.log("IDER-StartEx");
+ obj.m.userConsentFunc = userConsentFunc;
+ obj.m.imrsdk = CreateIMRSDKWrapper();
+ obj.m.imrsdk.InitEx(obj.m.client);
+ obj.m.imrsdk.RemoveAllClients();
+ if (obj.m.amtcertpath) { obj.m.imrsdk.SetCertificateInfo(obj.m.amtcertpath, null, null); }
+ obj.m.clientid = obj.m.imrsdk.AddClient(obj.m.tls + 1, obj.m.host);
+ globalIderPendingCalls++;
+ //console.log('IDEROpenTCPSessionAsync-call');
+ var error = obj.m.imrsdk.IDEROpenTCPSessionAsync(obj.m.clientid, obj.m.user, obj.m.pass, obj.m.imgpath, obj.m.isopath, function (error) {
+ //console.log('IDEROpenTCPSessionAsync-callback(' + error + ')');
+ globalIderPendingCalls--;
+ if (obj.m.imrsdk == null) return; // We closed already, exit now.
+ if ((error == 38) && (userConsentFunc != undefined)) { obj.m.Stop(); userConsentFunc(startIderSession); return; }
+ if (error != 0) { console.log('IDER error ' + error); obj.m.Stop(); }
+ if (error == 0) {
+ globalIderPendingCalls++;
+ obj.m.imrsdk.IDERSetDeviceStateAsync(obj.m.clientid, 0, obj.m.startoption, 0, obj.m.startoption, function (error, result) {
+ globalIderPendingCalls--;
+ if (error != 0) {
+ obj.m.Stop();
+ obj.m.onDialogPrompt(obj.m, { 'html': e }, 1);
+ } else {
+ obj.StateChange(3);
+ }
+ });
+ }
+ });
+ } catch (e) {
+ //console.log(e);
+ obj.m.Stop();
+ obj.m.onDialogPrompt(obj.m, { 'html': e }, 1);
+ }
+ }
+
+ return obj;
+}
diff --git a/amt-ider-server-ws-0.0.1.js b/amt-ider-server-ws-0.0.1.js
new file mode 100644
index 0000000..d2ff62e
--- /dev/null
+++ b/amt-ider-server-ws-0.0.1.js
@@ -0,0 +1,100 @@
+/**
+* @description IDER Handling Module
+* @author Ylian Saint-Hilaire
+* @version v0.0.2
+*/
+
+// Construct a Intel AMT Server IDER object
+var CreateAmtRemoteServerIder = function () {
+ var obj = {};
+ obj.protocol = 4; // IDER-Server
+
+ obj.iderStart = 0; // OnReboot = 0, Graceful = 1, Now = 2
+ obj.floppy = null;
+ obj.cdrom = null;
+ obj.state = 0;
+ obj.onStateChanged = null;
+ obj.m = {
+ sectorStats: null,
+ onDialogPrompt: null,
+ dialogPrompt: function (data) { obj.socket.send(JSON.stringify({ action: 'dialogResponse', args: data })); },
+ bytesToAmt: 0,
+ bytesFromAmt: 0,
+ server: true,
+ Stop: function () { obj.Stop(); }
+ };
+
+ // Private method
+ function debug() { if (urlvars && urlvars['idertrace']) { console.log(...arguments); } }
+
+ // Private method, called by parent when it change state
+ obj.xxStateChange = function (newstate) {
+ if (obj.state == newstate) return;
+ debug("SIDER-StateChange", newstate);
+ obj.state = newstate;
+ if (obj.onStateChanged != null) { obj.onStateChanged(obj, obj.state); }
+ }
+
+ obj.Start = function (host, port, user, pass, tls) {
+ debug("SIDER-Start", host, port, user, pass, tls);
+ obj.host = host;
+ obj.port = port;
+ obj.user = user;
+ obj.pass = pass;
+ obj.connectstate = 0;
+ obj.socket = new WebSocket(window.location.protocol.replace("http", "ws") + "//" + window.location.host + window.location.pathname.substring(0, window.location.pathname.lastIndexOf('/')) + "/webider.ashx?host=" + host + "&port=" + port + "&tls=" + tls + ((user == '*') ? "&serverauth=1" : "") + ((typeof pass === "undefined") ? ("&serverauth=1&user=" + user) : "") + "&tls1only=" + obj.tlsv1only);
+ obj.socket.onopen = obj.xxOnSocketConnected;
+ obj.socket.onmessage = obj.xxOnMessage;
+ obj.socket.onclose = obj.xxOnSocketClosed;
+ obj.xxStateChange(1);
+ }
+
+ obj.Stop = function () {
+ debug("SIDER-Stop");
+ if (obj.socket != null) { obj.socket.close(); obj.socket = null; }
+ obj.xxStateChange(0);
+ }
+
+ obj.xxOnSocketConnected = function () {
+ obj.xxStateChange(2);
+ obj.socket.send(JSON.stringify({ action: 'start' }));
+ }
+
+ obj.xxOnMessage = function (data) {
+ var msg = null;
+ try { msg = JSON.parse(data.data); } catch (ex) { }
+ if ((msg == null) || (typeof msg.action != 'string')) return;
+
+ switch (msg.action) {
+ case 'dialog': {
+ if (obj.m.onDialogPrompt != null) { obj.m.onDialogPrompt(obj, msg.args, msg.buttons); }
+ break;
+ }
+ case 'state': {
+ if (msg.state == 2) { obj.xxStateChange(3); }
+ break;
+ }
+ case 'stats': {
+ obj.m.bytesToAmt = msg.toAmt;
+ obj.m.bytesFromAmt = msg.fromAmt;
+ if (obj.m.sectorStats) { obj.m.sectorStats(msg.mode, msg.dev, msg.total, msg.start, msg.len); }
+ break;
+ }
+ case 'error': {
+ var iderErrorStrings = ["", "Floppy disk image does not exist", "Invalid floppy disk image", "Unable to open floppy disk image", "CDROM disk image does not exist", "Invalid CDROM disk image", "Unable to open CDROM disk image", "Can't perform IDER with no disk images"];
+ console.log('IDER Error: ' + iderErrorStrings[msg.code]);
+ // TODO: Display dialog box this error.
+ break;
+ }
+ default: {
+ console.log('Unknown Server IDER action: ' + msg.action);
+ breal;
+ }
+ }
+
+ }
+
+ obj.xxOnSocketClosed = function () { obj.Stop(); }
+
+ return obj;
+}
diff --git a/amt-ider-ws-0.0.1.js b/amt-ider-ws-0.0.1.js
new file mode 100644
index 0000000..77084ae
--- /dev/null
+++ b/amt-ider-ws-0.0.1.js
@@ -0,0 +1,692 @@
+/**
+* @description IDER Handling Module
+* @author Ylian Saint-Hilaire
+* @version v0.0.2
+*/
+
+// Construct a Intel AMT IDER object
+var CreateAmtRemoteIder = function () {
+ var obj = {};
+ obj.protocol = 3; // IDER
+ obj.bytesToAmt = 0;
+ obj.bytesFromAmt = 0;
+ obj.rx_timeout = 30000; // Default 30000
+ obj.tx_timeout = 0; // Default 0
+ obj.heartbeat = 20000; // Default 20000
+ obj.version = 1;
+ obj.acc = "";
+ obj.inSequence = 0;
+ obj.outSequence = 0;
+ obj.iderinfo = null;
+ obj.enabled = false;
+ obj.iderStart = 0; // OnReboot = 0, Graceful = 1, Now = 2
+ obj.floppy = null;
+ obj.cdrom = null;
+ obj.floppyReady = false;
+ obj.cdromReady = false;
+ //obj.pingTimer = null;
+ // ###BEGIN###{IDERStats}
+ obj.sectorStats = null;
+ // ###END###{IDERStats}
+
+ // Private method
+ // ###BEGIN###{IDERDebug}
+ function debug() { if (urlvars && urlvars['idertrace']) { console.log(...arguments); } }
+ // ###END###{IDERDebug}
+
+ // Mode Sense
+ var IDE_ModeSence_LS120Disk_Page_Array = String.fromCharCode(0x00, 0x26, 0x31, 0x80, 0x00, 0x00, 0x00, 0x00, 0x05, 0x1E, 0x10, 0xA9, 0x08, 0x20, 0x02, 0x00, 0x03, 0xC3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xD0, 0x00, 0x00);
+ var IDE_ModeSence_3F_LS120_Array = String.fromCharCode(0x00, 0x5c, 0x24, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0a, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x16, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x05, 0x1E, 0x10, 0xA9, 0x08, 0x20, 0x02, 0x00, 0x03, 0xC3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xD0, 0x00, 0x00, 0x08, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x06, 0x00, 0x00, 0x00, 0x11, 0x24, 0x31);
+ var IDE_ModeSence_FloppyDisk_Page_Array = String.fromCharCode(0x00, 0x26, 0x24, 0x80, 0x00, 0x00, 0x00, 0x00, 0x05, 0x1E, 0x04, 0xB0, 0x02, 0x12, 0x02, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xD0, 0x00, 0x00);
+ var IDE_ModeSence_3F_Floppy_Array = String.fromCharCode(0x00, 0x5c, 0x24, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0a, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x16, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x05, 0x1e, 0x04, 0xb0, 0x02, 0x12, 0x02, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xd0, 0x00, 0x00, 0x08, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x06, 0x00, 0x00, 0x00, 0x11, 0x24, 0x31);
+ var IDE_ModeSence_CD_1A_Array = String.fromCharCode(0x00, 0x12, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
+ //var IDE_ModeSence_CD_1B_Array = String.fromCharCode(0x00, 0x12, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x0A, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
+ var IDE_ModeSence_CD_1D_Array = String.fromCharCode(0x00, 0x12, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x1D, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
+ var IDE_ModeSence_CD_2A_Array = String.fromCharCode(0x00, 0x20, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x18, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
+ //var IDE_ModeSence_CD_01_Array = String.fromCharCode(0x00, 0x0E, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00);
+ var IDE_ModeSence_3F_CD_Array = String.fromCharCode(0x00, 0x28, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x18, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
+
+ // 0x46 constant data
+ var IDE_CD_ConfigArrayHeader = String.fromCharCode(0x00, 0x00,0x00, 0x28, 0x00, 0x00, 0x00, 0x08);
+ var IDE_CD_ConfigArrayProfileList = String.fromCharCode(0x00, 0x00, 0x03, 0x04, 0x00, 0x08, 0x01, 0x00);
+ var IDE_CD_ConfigArrayCore = String.fromCharCode(0x00, 0x01, 0x03, 0x04, 0x00, 0x00, 0x00, 0x02);
+ var IDE_CD_Morphing = String.fromCharCode(0x00, 0x02, 0x03, 0x04, 0x00, 0x00, 0x00, 0x00);
+ var IDE_CD_ConfigArrayRemovable = String.fromCharCode(0x00, 0x03, 0x03, 0x04, 0x29, 0x00, 0x00, 0x02);
+ var IDE_CD_ConfigArrayRandom = String.fromCharCode(0x00, 0x10, 0x01, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x01, 0x00, 0x00);
+ var IDE_CD_Read = String.fromCharCode(0x00, 0x1E, 0x03, 0x00);
+ var IDE_CD_PowerManagement = String.fromCharCode(0x01, 0x00, 0x03, 0x00);
+ var IDE_CD_Timeout = String.fromCharCode(0x01, 0x05, 0x03, 0x00);
+
+ // 0x01 constant data
+ var IDE_ModeSence_FloppyError_Recovery_Array = String.fromCharCode(0x00, 0x12, 0x24, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0A, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00);
+ var IDE_ModeSence_Ls120Error_Recovery_Array = String.fromCharCode(0x00, 0x12, 0x31, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0A, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00);
+ var IDE_ModeSence_CDError_Recovery_Array = String.fromCharCode(0x00, 0x0E, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00);
+
+
+ // Private method, called by parent when it change state
+ obj.xxStateChange = function (newstate) {
+ // ###BEGIN###{IDERDebug}
+ debug("IDER-StateChange", newstate);
+ // ###END###{IDERDebug}
+ if (newstate == 0) { obj.Stop(); }
+ if (newstate == 3) { obj.Start(); }
+ }
+
+ obj.Start = function () {
+ // ###BEGIN###{IDERDebug}
+ debug("IDER-Start");
+ debug(obj.floppy, obj.cdrom);
+ // ###END###{IDERDebug}
+ obj.bytesToAmt = 0;
+ obj.bytesFromAmt = 0;
+ obj.inSequence = 0;
+ obj.outSequence = 0;
+ g_readQueue = [];
+
+ // Send first command, OPEN_SESSION
+ obj.SendCommand(0x40, ShortToStrX(obj.rx_timeout) + ShortToStrX(obj.tx_timeout) + ShortToStrX(obj.heartbeat) + IntToStrX(obj.version));
+
+ // Send sector stats
+ // ###BEGIN###{IDERStats}
+ if (obj.sectorStats) {
+ obj.sectorStats(0, 0, obj.floppy?(obj.floppy.size >> 9):0);
+ obj.sectorStats(0, 1, obj.cdrom ? (obj.cdrom.size >> 11) : 0);
+ }
+ // ###END###{IDERStats}
+
+ // Setup the ping timer
+ //obj.pingTimer = setInterval(function () { obj.SendCommand(0x44); }, 5000);
+ }
+
+ obj.Stop = function () {
+ // ###BEGIN###{IDERDebug}
+ debug("IDER-Stop");
+ // ###END###{IDERDebug}
+ //if (obj.pingTimer) { clearInterval(obj.pingTimer); obj.pingTimer = null; }
+ obj.parent.Stop();
+ }
+
+ // Private method
+ obj.ProcessData = function (data) {
+ obj.bytesFromAmt += data.length;
+ obj.acc += data;
+ // ###BEGIN###{IDERDebug}
+ debug('IDER-ProcessData', obj.acc.length, rstr2hex(obj.acc));
+ // ###END###{IDERDebug}
+
+ // Process as many commands as possible
+ while (true) {
+ var len = obj.ProcessDataEx();
+ if (len == 0) return;
+ if (obj.inSequence != ReadIntX(obj.acc, 4)) {
+ // ###BEGIN###{IDERDebug}
+ debug('ERROR: Out of sequence', obj.inSequence, ReadIntX(obj.acc, 4));
+ // ###END###{IDERDebug}
+ obj.Stop();
+ return;
+ }
+ obj.inSequence++;
+ obj.acc = obj.acc.substring(len);
+ }
+ }
+
+ // Private method
+ obj.SendCommand = function (cmdid, data, completed, dma) {
+ if (data == null) { data = ''; }
+ var attributes = ((cmdid > 50) && (completed == true)) ? 2 : 0;
+ if (dma) { attributes += 1; }
+ var x = String.fromCharCode(cmdid, 0, 0, attributes) + IntToStrX(obj.outSequence++) + data;
+ obj.parent.xxSend(x);
+ obj.bytesToAmt += x.length;
+ // ###BEGIN###{IDERDebug}
+ if (cmdid != 0x4B) { debug('IDER-SendData', x.length, rstr2hex(x)); }
+ // ###END###{IDERDebug}
+ }
+
+ // CommandEndResponse (SCSI_SENSE)
+ obj.SendCommandEndResponse = function (error, sense, device, asc, asq) {
+ if (error) { obj.SendCommand(0x51, String.fromCharCode(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xc5, 0, 3, 0, 0, 0, device, 0x50, 0, 0, 0), true); }
+ else { obj.SendCommand(0x51, String.fromCharCode(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x87, (sense << 4), 3, 0, 0, 0, device, 0x51, sense, asc, asq), true); }
+ }
+
+ // DataToHost (SCSI_READ)
+ obj.SendDataToHost = function (device, completed, data, dma) {
+ var dmalen = (dma) ? 0 : data.length;
+ if (completed == true) {
+ obj.SendCommand(0x54, String.fromCharCode(0, (data.length & 0xff), (data.length >> 8), 0, dma ? 0xb4 : 0xb5, 0, 2, 0, (dmalen & 0xff), (dmalen >> 8), device, 0x58, 0x85, 0, 3, 0, 0, 0, device, 0x50, 0, 0, 0, 0, 0, 0) + data, completed, dma);
+ } else {
+ obj.SendCommand(0x54, String.fromCharCode(0, (data.length & 0xff), (data.length >> 8), 0, dma ? 0xb4 : 0xb5, 0, 2, 0, (dmalen & 0xff), (dmalen >> 8), device, 0x58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) + data, completed, dma);
+ }
+ }
+
+ // GetDataFromHost (SCSI_CHUNK)
+ obj.SendGetDataFromHost = function (device, chunksize) {
+ obj.SendCommand(0x52, String.fromCharCode(0, (chunksize & 0xff), (chunksize >> 8), 0, 0xb5, 0, 0, 0, (chunksize & 0xff), (chunksize >> 8), device, 0x58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), false);
+ }
+
+ // DisableEnableFeatures (STATUS_DATA)
+ // If type is REGS_TOGGLE (3), 4 bytes of data must be provided.
+ obj.SendDisableEnableFeatures = function (type, data) { if (data == null) { data = ''; } obj.SendCommand(0x48, String.fromCharCode(type) + data); }
+
+ // Private method
+ obj.ProcessDataEx = function () {
+ if (obj.acc.length < 8) return 0;
+
+ // First 8 bytes are the header
+ // CommandID + 0x000000 + Sequence Number
+
+ switch(obj.acc.charCodeAt(0)) {
+ case 0x41: // OPEN_SESSION
+ if (obj.acc.length < 30) return 0;
+ var len = obj.acc.charCodeAt(29);
+ if (obj.acc.length < (30 + len)) return 0;
+ obj.iderinfo = {};
+ obj.iderinfo.major = obj.acc.charCodeAt(8);
+ obj.iderinfo.minor = obj.acc.charCodeAt(9);
+ obj.iderinfo.fwmajor = obj.acc.charCodeAt(10);
+ obj.iderinfo.fwminor = obj.acc.charCodeAt(11);
+ obj.iderinfo.readbfr = ReadShortX(obj.acc, 16);
+ obj.iderinfo.writebfr = ReadShortX(obj.acc, 18);
+ obj.iderinfo.proto = obj.acc.charCodeAt(21);
+ obj.iderinfo.iana = ReadIntX(obj.acc, 25);
+ // ###BEGIN###{IDERDebug}
+ debug(obj.iderinfo);
+ // ###END###{IDERDebug}
+
+ if (obj.iderinfo.proto != 0) {
+ // ###BEGIN###{IDERDebug}
+ debug("Unknown proto", obj.iderinfo.proto);
+ // ###END###{IDERDebug}
+ obj.Stop();
+ }
+ if (obj.iderinfo.readbfr > 8192) {
+ // ###BEGIN###{IDERDebug}
+ debug("Illegal read buffer size", obj.iderinfo.readbfr);
+ // ###END###{IDERDebug}
+ obj.Stop();
+ }
+ if (obj.iderinfo.writebfr > 8192) {
+ // ###BEGIN###{IDERDebug}
+ debug("Illegal write buffer size", obj.iderinfo.writebfr);
+ // ###END###{IDERDebug}
+ obj.Stop();
+ }
+
+ if (obj.iderStart == 0) { obj.SendDisableEnableFeatures(3, IntToStrX(0x01 + 0x08)); } // OnReboot
+ else if (obj.iderStart == 1) { obj.SendDisableEnableFeatures(3, IntToStrX(0x01 + 0x10)); } // Graceful
+ else if (obj.iderStart == 2) { obj.SendDisableEnableFeatures(3, IntToStrX(0x01 + 0x18)); } // Now
+ //obj.SendDisableEnableFeatures(1); // GetSupportedFeatures
+ return 30 + len;
+ case 0x43: // CLOSE
+ // ###BEGIN###{IDERDebug}
+ debug('CLOSE');
+ // ###END###{IDERDebug}
+ obj.Stop();
+ return 8;
+ case 0x44: // KEEPALIVEPING
+ obj.SendCommand(0x45); // Send PONG back
+ return 8;
+ case 0x45: // KEEPALIVEPONG
+ // ###BEGIN###{IDERDebug}
+ debug('PONG');
+ // ###END###{IDERDebug}
+ return 8;
+ case 0x46: // RESETOCCURED
+ if (obj.acc.length < 9) return 0;
+ var resetMask = obj.acc.charCodeAt(8);
+ if (g_media === null) {
+ // No operations are pending
+ obj.SendCommand(0x47); // Send ResetOccuredResponse
+ // ###BEGIN###{IDERDebug}
+ debug('RESETOCCURED1', resetMask);
+ // ###END###{IDERDebug}
+ } else {
+ // Operations are being done, sent the reset once completed.
+ g_reset = true;
+ // ###BEGIN###{IDERDebug}
+ debug('RESETOCCURED2', resetMask);
+ // ###END###{IDERDebug}
+ }
+ return 9;
+ case 0x49: // STATUS_DATA - DisableEnableFeaturesReply
+ if (obj.acc.length < 13) return 0;
+ var type = obj.acc.charCodeAt(8);
+ var value = ReadIntX(obj.acc, 9);
+ // ###BEGIN###{IDERDebug}
+ debug('STATUS_DATA', type, value);
+ // ###END###{IDERDebug}
+ switch (type)
+ {
+ case 1: // REGS_AVAIL
+ if (value & 1) {
+ if (obj.iderStart == 0) { obj.SendDisableEnableFeatures(3, IntToStrX(0x01 + 0x08)); } // OnReboot
+ else if (obj.iderStart == 1) { obj.SendDisableEnableFeatures(3, IntToStrX(0x01 + 0x10)); } // Graceful
+ else if (obj.iderStart == 2) { obj.SendDisableEnableFeatures(3, IntToStrX(0x01 + 0x18)); } // Now
+ }
+ break;
+ case 2: // REGS_STATUS
+ obj.enabled = (value & 2) ? true : false;
+ // ###BEGIN###{IDERDebug}
+ debug("IDER Status: " + obj.enabled);
+ // ###END###{IDERDebug}
+ break;
+ case 3: // REGS_TOGGLE
+ if (value != 1) {
+ // ###BEGIN###{IDERDebug}
+ debug("Register toggle failure");
+ // ###END###{IDERDebug}
+ } //else { obj.SendDisableEnableFeatures(2); }
+ break;
+ }
+ return 13;
+ case 0x4A: // ERROR OCCURED
+ if (obj.acc.length < 11) return 0;
+ // ###BEGIN###{IDERDebug}
+ debug('IDER: ABORT', obj.acc.charCodeAt(8));
+ // ###END###{IDERDebug}
+ //obj.Stop();
+ return 11;
+ case 0x4B: // HEARTBEAT
+ // ###BEGIN###{IDERDebug}
+ //debug('HEARTBEAT');
+ // ###END###{IDERDebug}
+ return 8;
+ case 0x50: // COMMAND WRITTEN
+ if (obj.acc.length < 28) return 0;
+ var device = (obj.acc.charCodeAt(14) & 0x10) ? 0xB0 : 0xA0;
+ var deviceFlags = obj.acc.charCodeAt(14);
+ var cdb = obj.acc.substring(16, 28);
+ var featureRegister = obj.acc.charCodeAt(9);
+ // ###BEGIN###{IDERDebug}
+ debug('SCSI_CMD', device, rstr2hex(cdb), featureRegister, deviceFlags);
+ // ###END###{IDERDebug}
+ handleSCSI(device, cdb, featureRegister, deviceFlags);
+ return 28;
+ case 0x53: // DATA FROM HOST
+ if (obj.acc.length < 14) return 0;
+ var len = ReadShortX(obj.acc, 9);
+ if (obj.acc.length < (14 + len)) return 0;
+ // ###BEGIN###{IDERDebug}
+ debug('SCSI_WRITE, len = ' + (14 + len));
+ // ###END###{IDERDebug}
+ obj.SendCommand(0x51, String.fromCharCode(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87, 0x70, 0x03, 0x00, 0x00, 0x00, 0xa0, 0x51, 0x07, 0x27, 0x00), true);
+ return 14 + len;
+ default:
+ // ###BEGIN###{IDERDebug}
+ debug('Unknown IDER command', obj.acc[0]);
+ // ###END###{IDERDebug}
+ obj.Stop();
+ break;
+ }
+ return 0;
+ }
+
+ function handleSCSI(dev, cdb, featureRegister, deviceFlags)
+ {
+ var lba;
+ var len;
+
+ switch(cdb.charCodeAt(0))
+ {
+ case 0x00: // TEST_UNIT_READY:
+ // ###BEGIN###{IDERDebug}
+ debug("SCSI: TEST_UNIT_READY", dev);
+ // ###END###{IDERDebug}
+ switch (dev) {
+ case 0xA0: // DEV_FLOPPY
+ if (obj.floppy == null) { obj.SendCommandEndResponse(1, 0x02, dev, 0x3a, 0x00); return -1; }
+ if (obj.floppyReady == false) { obj.floppyReady = true; obj.SendCommandEndResponse(1, 0x06, dev, 0x28, 0x00); return -1; } // Switch to ready
+ break;
+ case 0xB0: // DEV_CDDVD
+ if (obj.cdrom == null) { obj.SendCommandEndResponse(1, 0x02, dev, 0x3a, 0x00); return -1; }
+ if (obj.cdromReady == false) { obj.cdromReady = true; obj.SendCommandEndResponse(1, 0x06, dev, 0x28, 0x00); return -1; } // Switch to ready
+ break;
+ default:
+ // ###BEGIN###{IDERDebug}
+ debug("SCSI Internal error 3", dev);
+ // ###END###{IDERDebug}
+ return -1;
+ }
+ obj.SendCommandEndResponse(1, 0x00, dev, 0x00, 0x00); // Indicate ready
+ break;
+ case 0x08: // READ_6
+ lba = ((cdb.charCodeAt(1) & 0x1f) << 16) + (cdb.charCodeAt(2) << 8) + cdb.charCodeAt(3);
+ len = cdb.charCodeAt(4);
+ if (len == 0) { len = 256; }
+ // ###BEGIN###{IDERDebug}
+ debug("SCSI: READ_6", dev, lba, len);
+ // ###END###{IDERDebug}
+ sendDiskData(dev, lba, len, featureRegister);
+ break;
+ case 0x0a: // WRITE_6
+ lba = ((cdb.charCodeAt(1) & 0x1f) << 16) + (cdb.charCodeAt(2) << 8) + cdb.charCodeAt(3);
+ len = cdb.charCodeAt(4);
+ if (len == 0) { len = 256; }
+ // ###BEGIN###{IDERDebug}
+ debug("SCSI: WRITE_6", dev, lba, len);
+ // ###END###{IDERDebug}
+ obj.SendCommandEndResponse(1, 0x02, dev, 0x3a, 0x00); // Write is not supported, remote no medium.
+ return -1;
+ /*
+ case 0x15: // MODE_SELECT_6:
+ // ###BEGIN###{IDERDebug}
+ debug("SCSI ERROR: MODE_SELECT_6", dev);
+ // ###END###{IDERDebug}
+ obj.SendCommandEndResponse(1, 0x05, dev, 0x20, 0x00);
+ return -1;
+ */
+ case 0x1a: // MODE_SENSE_6
+ // ###BEGIN###{IDERDebug}
+ debug("SCSI: MODE_SENSE_6", dev);
+ // ###END###{IDERDebug}
+ if ((cdb.charCodeAt(2) == 0x3f) && (cdb.charCodeAt(3) == 0x00)) {
+ var a = 0, b = 0;
+ switch (dev) {
+ case 0xA0: // DEV_FLOPPY
+ if (obj.floppy == null) { obj.SendCommandEndResponse(1, 0x02, dev, 0x3a, 0x00); return -1; }
+ a = 0x00;
+ b = 0x80; // Read only = 0x80, Read write = 0x00
+ break;
+ case 0xB0: // DEV_CDDVD
+ if (obj.cdrom == null) { obj.SendCommandEndResponse(1, 0x02, dev, 0x3a, 0x00); return -1; }
+ a = 0x05;
+ b = 0x80;
+ break;
+ default:
+ // ###BEGIN###{IDERDebug}
+ debug("SCSI Internal error 6", dev);
+ // ###END###{IDERDebug}
+ return -1;
+ }
+ obj.SendDataToHost(dev, true, String.fromCharCode(0, a, b, 0), featureRegister & 1);
+ return;
+ }
+ obj.SendCommandEndResponse(1, 0x05, dev, 0x24, 0x00);
+ break;
+ case 0x1b: // START_STOP (Called when you eject the CDROM)
+ //var immediate = cdb.charCodeAt(1) & 0x01;
+ //var loej = cdb.charCodeAt(4) & 0x02;
+ //var start = cdb.charCodeAt(4) & 0x01;
+ obj.SendCommandEndResponse(1, 0, dev);
+ break;
+ case 0x1e: // LOCK_UNLOCK - ALLOW_MEDIUM_REMOVAL
+ // ###BEGIN###{IDERDebug}
+ debug("SCSI: ALLOW_MEDIUM_REMOVAL", dev);
+ // ###END###{IDERDebug}
+ if ((dev == 0xA0) && (obj.floppy == null)) { obj.SendCommandEndResponse(1, 0x02, dev, 0x3a, 0x00); return -1; }
+ if ((dev == 0xB0) && (obj.cdrom == null)) { obj.SendCommandEndResponse(1, 0x02, dev, 0x3a, 0x00); return -1; }
+ obj.SendCommandEndResponse(1, 0x00, dev, 0x00, 0x00);
+ break;
+ case 0x23: // READ_FORMAT_CAPACITIES (Floppy only)
+ // ###BEGIN###{IDERDebug}
+ debug("SCSI: READ_FORMAT_CAPACITIES", dev);
+ // ###END###{IDERDebug}
+ var buflen = ReadShort(cdb, 7);
+ var mediaStatus = 0, sectors;
+ var mcSize = buflen / 8; // Capacity descriptor size is 8
+
+ switch (dev) {
+ case 0xA0: // DEV_FLOPPY
+ if ((obj.floppy == null) || (obj.floppy.size == 0)) { obj.SendCommandEndResponse(0, 0x05, dev, 0x24, 0x00); return -1; }
+ sectors = (obj.floppy.size >> 9) - 1;
+ break;
+ case 0xB0: // DEV_CDDVD
+ if ((obj.cdrom == null) || (obj.cdrom.size == 0)) { obj.SendCommandEndResponse(0, 0x05, dev, 0x24, 0x00); return -1; }
+ sectors = (obj.cdrom.size >> 11) - 1; // Number 2048 byte blocks
+ break;
+ default:
+ // ###BEGIN###{IDERDebug}
+ debug("SCSI Internal error 4", dev);
+ // ###END###{IDERDebug}
+ return -1;
+ }
+
+ obj.SendDataToHost(dev, true, IntToStr(8) + String.fromCharCode(0x00, 0x00, 0x0b, 0x40, 0x02, 0x00, 0x02, 0x00), featureRegister & 1);
+ break;
+ case 0x25: // READ_CAPACITY
+ // ###BEGIN###{IDERDebug}
+ debug("SCSI: READ_CAPACITY", dev);
+ // ###END###{IDERDebug}
+ var len = 0;
+ switch(dev)
+ {
+ case 0xA0: // DEV_FLOPPY
+ if ((obj.floppy == null) || (obj.floppy.size == 0)) { obj.SendCommandEndResponse(0, 0x02, dev, 0x3a, 0x00); return -1; }
+ if (obj.floppy != null) { len = (obj.floppy.size >> 9) - 1; }
+ // ###BEGIN###{IDERDebug}
+ debug('DEV_FLOPPY', len); // Number 512 byte blocks
+ // ###END###{IDERDebug}
+ break;
+ case 0xB0: // DEV_CDDVD
+ if ((obj.cdrom == null) || (obj.cdrom.size == 0)) { obj.SendCommandEndResponse(0, 0x02, dev, 0x3a, 0x00); return -1; }
+ if (obj.cdrom != null) { len = (obj.cdrom.size >> 11) - 1; } // Number 2048 byte blocks
+ // ###BEGIN###{IDERDebug}
+ debug('DEV_CDDVD', len);
+ // ###END###{IDERDebug}
+ break;
+ default:
+ // ###BEGIN###{IDERDebug}
+ debug("SCSI Internal error 4", dev);
+ // ###END###{IDERDebug}
+ return -1;
+ }
+ //if (dev == 0xA0) { dev = 0x00; } else { dev = 0x10; } // Weird but seems to work.
+ // ###BEGIN###{IDERDebug}
+ debug("SCSI: READ_CAPACITY2", dev, deviceFlags);
+ // ###END###{IDERDebug}
+ obj.SendDataToHost(deviceFlags, true, IntToStr(len) + String.fromCharCode(0, 0, ((dev == 0xB0) ? 0x08 : 0x02), 0), featureRegister & 1);
+ break;
+ case 0x28: // READ_10
+ lba = ReadInt(cdb, 2);
+ len = ReadShort(cdb, 7);
+ // ###BEGIN###{IDERDebug}
+ debug("SCSI: READ_10", dev, lba, len);
+ // ###END###{IDERDebug}
+ sendDiskData(dev, lba, len, featureRegister);
+ break;
+ case 0x2a: // WRITE_10 (Floppy only)
+ case 0x2e: // WRITE_AND_VERIFY (Floppy only)
+ lba = ReadInt(cdb, 2);
+ len = ReadShort(cdb, 7);
+ // ###BEGIN###{IDERDebug}
+ debug("SCSI: WRITE_10", dev, lba, len);
+ // ###END###{IDERDebug}
+ obj.SendGetDataFromHost(dev, 512 * len); // Floppy writes only, accept sectors of 512 bytes
+ break;
+ case 0x43: // READ_TOC (CD Audio only)
+ var buflen = ReadShort(cdb, 7);
+ var msf = cdb.charCodeAt(1) & 0x02;
+ var format = cdb.charCodeAt(2) & 0x07;
+ if (format == 0) { format = cdb.charCodeAt(9) >> 6; }
+ // ###BEGIN###{IDERDebug}
+ debug("SCSI: READ_TOC, dev=" + dev + ", buflen=" + buflen + ", msf=" + msf + ", format=" + format);
+ // ###END###{IDERDebug}
+
+ switch (dev) {
+ case 0xA0: // DEV_FLOPPY
+ obj.SendCommandEndResponse(1, 0x05, dev, 0x20, 0x00); // Not implemented
+ return -1;
+ case 0xB0: // DEV_CDDVD
+ // NOP
+ break;
+ default:
+ // ###BEGIN###{IDERDebug}
+ debug("SCSI Internal error 9", dev);
+ // ###END###{IDERDebug}
+ return -1;
+ }
+
+ if (format == 1) { obj.SendDataToHost(dev, true, String.fromCharCode(0x00, 0x0a, 0x01, 0x01, 0x00, 0x14, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00), featureRegister & 1); }
+ else if (format == 0) {
+ if (msf) {
+ obj.SendDataToHost(dev, true, String.fromCharCode(0x00, 0x12, 0x01, 0x01, 0x00, 0x14, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x14, 0xaa, 0x00, 0x00, 0x00, 0x34, 0x13), featureRegister & 1);
+ } else {
+ obj.SendDataToHost(dev, true, String.fromCharCode(0x00, 0x12, 0x01, 0x01, 0x00, 0x14, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00), featureRegister & 1);
+ }
+ }
+ break;
+ case 0x46: // GET_CONFIGURATION
+ var sendall = (cdb.charCodeAt(1) != 2);
+ var firstcode = ReadShort(cdb, 2);
+ var buflen = ReadShort(cdb, 7);
+
+ // ###BEGIN###{IDERDebug}
+ debug("SCSI: GET_CONFIGURATION", dev, sendall, firstcode, buflen);
+ // ###END###{IDERDebug}
+
+ if (buflen == 0) { obj.SendDataToHost(dev, true, IntToStr(0x003c) + IntToStr(0x0008), featureRegister & 1); return -1; } // TODO: Fixed this return, it's not correct.
+
+ // Set the header
+ var r = IntToStr(0x0008);
+
+ // Add the data
+ if (firstcode == 0) { r += IDE_CD_ConfigArrayProfileList; }
+ if ((firstcode == 0x1) || (sendall && (firstcode < 0x1))) { r += IDE_CD_ConfigArrayCore; }
+ if ((firstcode == 0x2) || (sendall && (firstcode < 0x2))) { r += IDE_CD_Morphing; }
+ if ((firstcode == 0x3) || (sendall && (firstcode < 0x3))) { r += IDE_CD_ConfigArrayRemovable; }
+ if ((firstcode == 0x10) || (sendall && (firstcode < 0x10))) { r += IDE_CD_ConfigArrayRandom; }
+ if ((firstcode == 0x1E) || (sendall && (firstcode < 0x1E))) { r += IDE_CD_Read; }
+ if ((firstcode == 0x100) || (sendall && (firstcode < 0x100))) { r += IDE_CD_PowerManagement; }
+ if ((firstcode == 0x105) || (sendall && (firstcode < 0x105))) { r += IDE_CD_Timeout; }
+
+ // Set the length
+ r = IntToStr(r.length) + r;
+
+ // Cut the length to buflen if needed
+ if (r.length > buflen) { r = r.substring(0, buflen); }
+
+ obj.SendDataToHost(dev, true, r, featureRegister & 1);
+ return -1;
+ case 0x4a: // GET_EV_STATUS - GET_EVENT_STATUS_NOTIFICATION
+ //var buflen = (cdb.charCodeAt(7) << 8) + cdb.charCodeAt(8);
+ //if (buflen == 0) { obj.SendDataToHost(dev, true, IntToStr(0x003c) + IntToStr(0x0008), featureRegister & 1); return -1; } // TODO: Fixed this return, it's not correct.
+ // ###BEGIN###{IDERDebug}
+ debug("SCSI: GET_EVENT_STATUS_NOTIFICATION", dev, cdb.charCodeAt(1), cdb.charCodeAt(4), cdb.charCodeAt(9));
+ // ###END###{IDERDebug}
+ if ((cdb.charCodeAt(1) != 0x01) && (cdb.charCodeAt(4) != 0x10)) {
+ // ###BEGIN###{IDERDebug}
+ debug('SCSI ERROR');
+ // ###END###{IDERDebug}
+ obj.SendCommandEndResponse(1, 0x05, dev, 0x26, 0x01);
+ break;
+ }
+ var present = 0x00;
+ if ((dev == 0xA0) && (obj.floppy != null)) { present = 0x02; }
+ else if ((dev == 0xB0) && (obj.cdrom != null)) { present = 0x02; }
+ obj.SendDataToHost(dev, true, String.fromCharCode(0x00, present, 0x80, 0x00), featureRegister & 1); // This is the original version, 4 bytes long
+ break;
+ case 0x4c:
+ obj.SendCommand(0x51, IntToStrX(0) + IntToStrX(0) + IntToStrX(0) + String.fromCharCode(0x87, 0x50, 0x03, 0x00, 0x00, 0x00, 0xb0, 0x51, 0x05, 0x20, 0x00), true);
+ break;
+ case 0x51: // READ_DISC_INFO
+ // ###BEGIN###{IDERDebug}
+ debug("SCSI READ_DISC_INFO", dev);
+ // ###END###{IDERDebug}
+ obj.SendCommandEndResponse(0, 0x05, dev, 0x20, 0x00); // Correct
+ return -1;
+ case 0x55: // MODE_SELECT_10:
+ // ###BEGIN###{IDERDebug}
+ debug("SCSI ERROR: MODE_SELECT_10", dev);
+ // ###END###{IDERDebug}
+ obj.SendCommandEndResponse(1, 0x05, dev, 0x20, 0x00);
+ return -1;
+ case 0x5a: // MODE_SENSE_10
+ // ###BEGIN###{IDERDebug}
+ debug("SCSI: MODE_SENSE_10", dev, cdb.charCodeAt(2) & 0x3f);
+ // ###END###{IDERDebug}
+ var buflen = ReadShort(cdb, 7);
+ //var pc = cdb.charCodeAt(2) & 0xc0;
+ var r = null;
+
+ if (buflen == 0) { obj.SendDataToHost(dev, true, IntToStr(0x003c) + IntToStr(0x0008), featureRegister & 1); return -1; } // TODO: Fixed this return, it's not correct.
+
+ // 1.44 mb floppy or LS120 (sectorCount == 0x3c300)
+ var sectorCount = 0;
+ if (dev == 0xA0) {
+ if (obj.floppy != null) { sectorCount = (obj.floppy.size >> 9); }
+ } else {
+ if (obj.cdrom != null) { sectorCount = (obj.cdrom.size >> 11); }
+ }
+
+ switch (cdb.charCodeAt(2) & 0x3f) {
+ case 0x01: if (dev == 0xA0) { r = (sectorCount <= 0xb40)?IDE_ModeSence_FloppyError_Recovery_Array:IDE_ModeSence_Ls120Error_Recovery_Array; } else { r = IDE_ModeSence_CDError_Recovery_Array; } break;
+ case 0x05: if (dev == 0xA0) { r = (sectorCount <= 0xb40)?IDE_ModeSence_FloppyDisk_Page_Array:IDE_ModeSence_LS120Disk_Page_Array; } break;
+ case 0x3f: if (dev == 0xA0) { r = (sectorCount <= 0xb40)?IDE_ModeSence_3F_Floppy_Array:IDE_ModeSence_3F_LS120_Array; } else { r = IDE_ModeSence_3F_CD_Array; } break;
+ case 0x1A: if (dev == 0xB0) { r = IDE_ModeSence_CD_1A_Array; } break;
+ case 0x1D: if (dev == 0xB0) { r = IDE_ModeSence_CD_1D_Array; } break;
+ case 0x2A: if (dev == 0xB0) { r = IDE_ModeSence_CD_2A_Array; } break;
+ }
+
+ if (r == null) {
+ obj.SendCommandEndResponse(0, 0x05, dev, 0x20, 0x00); // TODO: Send proper error!!!
+ } else {
+ // Set disk to read only (we don't support write).
+ //ms_data[3] = ms_data[3] | 0x80;
+ obj.SendDataToHost(dev, true, r, featureRegister & 1);
+ }
+ break;
+ default: // UNKNOWN COMMAND
+ // ###BEGIN###{IDERDebug}
+ debug("IDER: Unknown SCSI command", cdb.charCodeAt(0));
+ // ###END###{IDERDebug}
+ obj.SendCommandEndResponse(0, 0x05, dev, 0x20, 0x00);
+ return -1;
+ }
+ return 0;
+ }
+
+ function sendDiskData(dev, lba, len, featureRegister) {
+ var media = null;
+ var mediaBlocks = 0;
+ if (dev == 0xA0) { media = obj.floppy; if (obj.floppy != null) { mediaBlocks = (obj.floppy.size >> 9); } }
+ if (dev == 0xB0) { media = obj.cdrom; if (obj.cdrom != null) { mediaBlocks = (obj.cdrom.size >> 11); } }
+ if ((len < 0) || (lba + len > mediaBlocks)) { obj.SendCommandEndResponse(1, 0x05, dev, 0x21, 0x00); return 0; }
+ if (len == 0) { obj.SendCommandEndResponse(1, 0x00, dev, 0x00, 0x00); return 0; }
+ if (media != null) {
+ // Send sector stats
+ // ###BEGIN###{IDERStats}
+ if (obj.sectorStats) { obj.sectorStats(1, (dev == 0xA0) ? 0 : 1, mediaBlocks, lba, len); }
+ // ###END###{IDERStats}
+ if (dev == 0xA0) { lba <<= 9; len <<= 9; } else { lba <<= 11; len <<= 11; }
+ if (g_media !== null) {
+ // Queue read operation
+ g_readQueue.push({ media: media, dev: dev, lba: lba, len: len, fr: featureRegister });
+ } else {
+ // obj.iderinfo.readbfr // TODO: MaxRead
+ g_media = media;
+ g_dev = dev;
+ g_lba = lba;
+ g_len = len;
+ sendDiskDataEx(featureRegister);
+ }
+ }
+ }
+
+ var g_readQueue = [];
+ var g_reset = false;
+ var g_media = null;
+ var g_dev;
+ var g_lba;
+ var g_len;
+ function sendDiskDataEx(featureRegister) {
+ var len = g_len, lba = g_lba;
+ if (g_len > obj.iderinfo.readbfr) { len = obj.iderinfo.readbfr; }
+ g_len -= len;
+ g_lba += len;
+ var fr = new FileReader();
+ fr.onload = function () {
+ obj.SendDataToHost(g_dev, (g_len == 0), this.result, featureRegister & 1);
+ if ((g_len > 0) && (g_reset == false)) {
+ sendDiskDataEx(featureRegister);
+ } else {
+ g_media = null;
+ if (g_reset) { obj.SendCommand(0x47); g_readQueue = []; g_reset = false; } // Send ResetOccuredResponse
+ else if (g_readQueue.length > 0) { var op = g_readQueue.shift(); g_media = op.media; g_dev = op.dev; g_lba = op.lba; g_len = op.len; sendDiskDataEx(op.fr); } // Un-queue read operation
+ }
+ };
+ //console.log('Read from ' + lba + ' to ' + (lba + len) + ', total of ' + len);
+ fr.readAsBinaryString(g_media.slice(lba, lba + len));
+ }
+
+ return obj;
+}
diff --git a/amt-lms-0.0.1.js b/amt-lms-0.0.1.js
new file mode 100644
index 0000000..be22e97
--- /dev/null
+++ b/amt-lms-0.0.1.js
@@ -0,0 +1,104 @@
+/**
+* @description Intel AMT LMS control module - using websocket
+* @author Ylian Saint-Hilaire
+* @version v0.0.1
+*/
+
+// Construct a LMS control object
+var CreateLmsControl = function () {
+ var obj = {};
+ var socket = null;
+ obj.State = 0;
+ obj.onStateChanged = null;
+ obj.onData = null;
+
+ // Private method
+ obj.Start = function () {
+ socket = new WebSocket(window.location.protocol.replace("http", "ws") + "//" + window.location.host + "/lms.ashx");
+ socket.onopen = _OnSocketConnected;
+ socket.onmessage = _OnMessage;
+ socket.onclose = obj.Stop;
+ _StateChange(1);
+ }
+
+ function _OnSocketConnected() {
+ _StateChange(2);
+ }
+
+ // Setup the file reader
+ var fileReader = new FileReader();
+ var fileReaderInuse = false, fileReaderAcc = [];
+ if (fileReader.readAsBinaryString) {
+ // Chrome & Firefox (Draft)
+ fileReader.onload = function (e) { _OnSocketData(e.target.result); if (fileReaderAcc.length == 0) { fileReaderInuse = false; } else { fileReader.readAsBinaryString(new Blob([fileReaderAcc.shift()])); } }
+ } else if (fileReader.readAsArrayBuffer) {
+ // Chrome & Firefox (Spec)
+ fileReader.onloadend = function (e) { _OnSocketData(e.target.result); if (fileReaderAcc.length == 0) { fileReaderInuse = false; } else { fileReader.readAsArrayBuffer(fileReaderAcc.shift()); } }
+ }
+
+ function _OnMessage(e) {
+ if (typeof e.data == 'object') {
+ if (fileReaderInuse == true) { fileReaderAcc.push(e.data); return; }
+ if (fileReader.readAsBinaryString) {
+ // Chrome & Firefox (Draft)
+ fileReaderInuse = true;
+ fileReader.readAsBinaryString(new Blob([e.data]));
+ } else if (fileReader.readAsArrayBuffer) {
+ // Chrome & Firefox (Spec)
+ fileReaderInuse = true;
+ fileReader.readAsArrayBuffer(e.data);
+ } else {
+ // IE10, readAsBinaryString does not exist, use an alternative.
+ var binary = "", bytes = new Uint8Array(e.data), length = bytes.byteLength;
+ for (var i = 0; i < length; i++) { binary += String.fromCharCode(bytes[i]); }
+ _OnSocketData(binary);
+ }
+ } else {
+ _OnSocketData(e.data);
+ }
+ };
+
+ function _OnSocketData(data) {
+ if (!data) return;
+
+ if (typeof data === 'object') {
+ // This is an ArrayBuffer, convert it to a string array (used in IE)
+ var binary = "";
+ var bytes = new Uint8Array(data);
+ var length = bytes.byteLength;
+ for (var i = 0; i < length; i++) { binary += String.fromCharCode(bytes[i]); }
+ data = binary;
+ }
+ else if (typeof data !== 'string') { return; }
+
+ // Send the data up
+ if (obj.onData != null) obj.onData(obj, data);
+ }
+
+ function _Send(x) {
+ if (socket != null && socket.readyState == WebSocket.OPEN) {
+ var b = new Uint8Array(x.length);
+ for (var i = 0; i < x.length; ++i) { b[i] = x.charCodeAt(i); }
+ socket.send(b.buffer);
+ }
+ }
+
+ obj.SendCmd = function (cmdid, data) {
+ if (socket == null || obj.State != 2) return;
+ if (!data || data == null) data = "";
+ _Send(ShortToStrX(cmdid) + data);
+ }
+
+ function _StateChange(newstate) {
+ if (obj.State == newstate) return;
+ obj.State = newstate;
+ if (obj.onStateChanged != null) obj.onStateChanged(obj, obj.State);
+ }
+
+ obj.Stop = function () {
+ _StateChange(0);
+ if (socket != null) { socket.close(); socket = null; }
+ }
+
+ return obj;
+}
\ No newline at end of file
diff --git a/amt-redir-node-0.1.0.js b/amt-redir-node-0.1.0.js
new file mode 100644
index 0000000..fba1952
--- /dev/null
+++ b/amt-redir-node-0.1.0.js
@@ -0,0 +1,323 @@
+/**
+* @description Intel AMT Redirection Transport Module - using Node
+* @author Ylian Saint-Hilaire
+* @version v0.0.1f
+*/
+
+// Construct a MeshServer object
+var CreateAmtRedirect = function (module) {
+ var obj = {};
+ obj.m = module; // This is the inner module (Terminal or Desktop)
+ module.parent = obj;
+ obj.State = 0;
+ obj.net = require('net');
+ obj.tls = require('tls');
+ obj.crypto = require('crypto');
+ obj.constants = require('constants');
+ obj.socket = null;
+ obj.host = null;
+ obj.port = 0;
+ obj.user = null;
+ obj.pass = null;
+ obj.connectstate = 0;
+ obj.protocol = module.protocol; // 1 = SOL, 2 = KVM, 3 = IDER
+ obj.xtlsoptions = null;
+
+ obj.amtaccumulator = '';
+ obj.amtsequence = 1;
+ obj.amtkeepalivetimer = null;
+ obj.authuri = '/RedirectionService';
+ obj.digestRealmMatch = null;
+
+ obj.onStateChanged = null;
+
+ // Private method
+ //obj.Debug = function (msg) { console.log(msg); }
+
+ obj.Start = function (host, port, user, pass, tls, tlsFingerprint, tlsoptions) {
+ obj.host = host;
+ obj.port = port;
+ obj.user = user;
+ obj.pass = pass;
+ obj.xtls = tls;
+ obj.xtlsoptions = tlsoptions;
+ obj.xtlsFingerprint = tlsFingerprint;
+ obj.connectstate = 0;
+
+ if (obj.xtlsoptions && obj.xtlsoptions.meshServerConnect) {
+ // Use the websocket wrapper to connect to MeshServer server
+ obj.socket = CreateWebSocketWrapper(obj.xtlsoptions.host, obj.xtlsoptions.port, '/webrelay.ashx?user=' + encodeURIComponent(obj.xtlsoptions.username) + '&pass=' + encodeURIComponent(obj.xtlsoptions.password) + '&host=' + encodeURIComponent(obj.host) + '&p=2&tls=' + tlsFingerprint.xtls + '&tls1only=' + tlsFingerprint.xtlsMethod, obj.xtlsoptions.xtlsFingerprint);
+ obj.socket.setEncoding('binary');
+ obj.socket.ondata = obj.xxOnSocketData;
+ obj.socket.onclose = obj.xxOnSocketClosed;
+ obj.socket.connect(obj.xxOnSocketConnected);
+ } else if (tls == false) {
+ obj.socket = new obj.net.Socket();
+ obj.socket.setEncoding('binary');
+ obj.socket.connect(port, host, obj.xxOnSocketConnected);
+ obj.socket.on('data', obj.xxOnSocketData);
+ obj.socket.on('close', obj.xxOnSocketClosed);
+ obj.socket.on('error', obj.xxOnSocketClosed);
+ } else {
+ if (obj.xtlsoptions == null) { obj.xtlsoptions = { secureProtocol: 'TLSv1_method', ciphers: 'RSA+AES:!aNULL:!MD5:!DSS', secureOptions: obj.constants.SSL_OP_NO_SSLv2 | obj.constants.SSL_OP_NO_SSLv3 | obj.constants.SSL_OP_NO_COMPRESSION | obj.constants.SSL_OP_CIPHER_SERVER_PREFERENCE, rejectUnauthorized: false }; }
+ obj.socket = obj.tls.connect(port, host, obj.xtlsoptions, obj.xxOnSocketConnected);
+ obj.socket.setEncoding('binary');
+ obj.socket.on('data', obj.xxOnSocketData);
+ obj.socket.on('close', obj.xxOnSocketClosed);
+ obj.socket.on('error', obj.xxOnSocketClosed);
+ }
+ obj.xxStateChange(1);
+ }
+
+ // Get the certificate of Intel AMT
+ obj.getPeerCertificate = function () { if (obj.xtls == true) { return obj.socket.getPeerCertificate(); } return null; }
+
+ obj.xxOnSocketConnected = function () {
+ if (obj.socket == null) return;
+ if (!obj.xtlsoptions || !obj.xtlsoptions.meshServerConnect) {
+ if (obj.xtls == true) {
+ obj.xtlsCertificate = obj.socket.getPeerCertificate();
+ if ((obj.xtlsFingerprint != 0) && (obj.xtlsCertificate.fingerprint.split(':').join('').toLowerCase() != obj.xtlsFingerprint)) { obj.Stop(); return; }
+ }
+ }
+
+ if (urlvars && urlvars['redirtrace']) { console.log('REDIR-CONNECTED'); }
+ //obj.Debug("Socket Connected");
+ obj.xxStateChange(2);
+ if (obj.protocol == 1) obj.xxSend(obj.RedirectStartSol); // TODO: Put these strings in higher level module to tighten code
+ if (obj.protocol == 2) obj.xxSend(obj.RedirectStartKvm); // Don't need these is the feature if not compiled-in.
+ if (obj.protocol == 3) obj.xxSend(obj.RedirectStartIder);
+ }
+
+ obj.xxOnSocketData = function (data) {
+ if (!data || obj.connectstate == -1) return;
+ if (urlvars && urlvars['redirtrace']) { console.log('REDIR-RECV(' + data.length + '): ' + rstr2hex(data)); }
+ //obj.Debug("Recv(" + data.length + "): " + rstr2hex(data));
+ if ((obj.protocol == 2 || obj.protocol == 3) && obj.connectstate == 1) { return obj.m.ProcessData(data); } // KVM traffic, forward it directly.
+ obj.amtaccumulator += data;
+ //obj.Debug("Recv(" + obj.amtaccumulator.length + "): " + rstr2hex(obj.amtaccumulator));
+ while (obj.amtaccumulator.length >= 1) {
+ var cmdsize = 0;
+ switch (obj.amtaccumulator.charCodeAt(0)) {
+ case 0x11: // StartRedirectionSessionReply (17)
+ if (obj.amtaccumulator.length < 4) return;
+ var statuscode = obj.amtaccumulator.charCodeAt(1);
+ switch (statuscode) {
+ case 0: // STATUS_SUCCESS
+ if (obj.amtaccumulator.length < 13) return;
+ var oemlen = obj.amtaccumulator.charCodeAt(12);
+ if (obj.amtaccumulator.length < 13 + oemlen) return;
+ obj.xxSend(String.fromCharCode(0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00)); // Query authentication support
+ cmdsize = (13 + oemlen);
+ break;
+ default:
+ obj.Stop();
+ break;
+ }
+ break;
+ case 0x14: // AuthenticateSessionReply (20)
+ if (obj.amtaccumulator.length < 9) return;
+ var authDataLen = ReadIntX(obj.amtaccumulator, 5);
+ if (obj.amtaccumulator.length < 9 + authDataLen) return;
+ var status = obj.amtaccumulator.charCodeAt(1);
+ var authType = obj.amtaccumulator.charCodeAt(4);
+ var authData = [];
+ for (i = 0; i < authDataLen; i++) { authData.push(obj.amtaccumulator.charCodeAt(9 + i)); }
+ var authDataBuf = obj.amtaccumulator.substring(9, 9 + authDataLen);
+ cmdsize = 9 + authDataLen;
+ if (authType == 0) {
+ // ###BEGIN###{Mode-NodeWebkit}
+ if (obj.user == '*') {
+ if (authData.indexOf(2) >= 0) {
+ // Kerberos Auth
+ var ticket;
+ if (kerberos && kerberos != null) {
+ var ticketReturn = kerberos.getTicket('HTTP' + ((obj.tls == 1)?'S':'') + '/' + ((obj.pass == '') ? (obj.host + ':' + obj.port) : obj.pass));
+ if (ticketReturn.returnCode == 0 || ticketReturn.returnCode == 0x90312) {
+ ticket = ticketReturn.ticket;
+ if (process.platform.indexOf('win') >= 0) {
+ // Clear kerberos tickets on both 32 and 64bit Windows platforms
+ try { require('child_process').exec('%windir%\\system32\\klist purge', function (error, stdout, stderr) { if (error) { require('child_process').exec('%windir%\\sysnative\\klist purge', function (error, stdout, stderr) { if (error) { console.error('Unable to purge kerberos tickets'); } }); } }); } catch (e) { console.log(e); }
+ }
+ } else {
+ console.error('Unexpected Kerberos error code: ' + ticketReturn.returnCode);
+ }
+ }
+ if (ticket) {
+ obj.xxSend(String.fromCharCode(0x13, 0x00, 0x00, 0x00, 0x02) + IntToStrX(ticket.length) + ticket);
+ } else {
+ obj.Stop();
+ }
+ }
+ else obj.Stop();
+ } else {
+ // ###END###{Mode-NodeWebkit}
+ // Query
+ if (authData.indexOf(4) >= 0) {
+ // Good Digest Auth (With cnonce and all)
+ obj.xxSend(String.fromCharCode(0x13, 0x00, 0x00, 0x00, 0x04) + IntToStrX(obj.user.length + obj.authuri.length + 8) + String.fromCharCode(obj.user.length) + obj.user + String.fromCharCode(0x00, 0x00) + String.fromCharCode(obj.authuri.length) + obj.authuri + String.fromCharCode(0x00, 0x00, 0x00, 0x00));
+ }
+ else if (authData.indexOf(3) >= 0) {
+ // Bad Digest Auth (Not sure why this is supported, cnonce is not used!)
+ obj.xxSend(String.fromCharCode(0x13, 0x00, 0x00, 0x00, 0x03) + IntToStrX(obj.user.length + obj.authuri.length + 7) + String.fromCharCode(obj.user.length) + obj.user + String.fromCharCode(0x00, 0x00) + String.fromCharCode(obj.authuri.length) + obj.authuri + String.fromCharCode(0x00, 0x00, 0x00));
+ }
+ else if (authData.indexOf(1) >= 0) {
+ // Basic Auth (Probably a good idea to not support this unless this is an old version of Intel AMT)
+ obj.xxSend(String.fromCharCode(0x13, 0x00, 0x00, 0x00, 0x01) + IntToStrX(obj.user.length + obj.pass.length + 2) + String.fromCharCode(obj.user.length) + obj.user + String.fromCharCode(obj.pass.length) + obj.pass);
+ }
+ else obj.Stop();
+ // ###BEGIN###{Mode-NodeWebkit}
+ }
+ // ###END###{Mode-NodeWebkit}
+ }
+ else if ((authType == 3 || authType == 4) && status == 1) {
+ var curptr = 0;
+
+ // Realm
+ var realmlen = authDataBuf.charCodeAt(curptr);
+ var realm = authDataBuf.substring(curptr + 1, curptr + 1 + realmlen);
+ curptr += (realmlen + 1);
+
+ // Check the digest realm. If it does not match, close the connection.
+ if (obj.digestRealmMatch && (obj.digestRealmMatch != realm)) { obj.Stop(); return; }
+
+ // Nonce
+ var noncelen = authDataBuf.charCodeAt(curptr);
+ var nonce = authDataBuf.substring(curptr + 1, curptr + 1 + noncelen);
+ curptr += (noncelen + 1);
+
+ // QOP
+ var qoplen = 0;
+ var qop = null;
+ var cnonce = obj.xxRandomValueHex(32);
+ var snc = '00000002';
+ var extra = '';
+ if (authType == 4) {
+ qoplen = authDataBuf.charCodeAt(curptr);
+ qop = authDataBuf.substring(curptr + 1, curptr + 1 + qoplen);
+ curptr += (qoplen + 1);
+ extra = snc + ':' + cnonce + ':' + qop + ':';
+ }
+ var digest = hex_md5(hex_md5(obj.user + ':' + realm + ':' + obj.pass) + ':' + nonce + ':' + extra + hex_md5('POST:' + obj.authuri));
+
+ var totallen = obj.user.length + realm.length + nonce.length + obj.authuri.length + cnonce.length + snc.length + digest.length + 7;
+ if (authType == 4) totallen += (qop.length + 1);
+ var buf = String.fromCharCode(0x13, 0x00, 0x00, 0x00, authType) + IntToStrX(totallen) + String.fromCharCode(obj.user.length) + obj.user + String.fromCharCode(realm.length) + realm + String.fromCharCode(nonce.length) + nonce + String.fromCharCode(obj.authuri.length) + obj.authuri + String.fromCharCode(cnonce.length) + cnonce + String.fromCharCode(snc.length) + snc + String.fromCharCode(digest.length) + digest;
+ if (authType == 4) buf += (String.fromCharCode(qop.length) + qop);
+ obj.xxSend(buf);
+ }
+ else if (status == 0) { // Success
+ if (obj.protocol == 1) {
+ // Serial-over-LAN: Send Intel AMT serial settings...
+ var MaxTxBuffer = 10000;
+ var TxTimeout = 100;
+ var TxOverflowTimeout = 0;
+ var RxTimeout = 10000;
+ var RxFlushTimeout = 100;
+ var Heartbeat = 0;//5000;
+ obj.xxSend(String.fromCharCode(0x20, 0x00, 0x00, 0x00) + ToIntStr(obj.amtsequence++) + ToShortStr(MaxTxBuffer) + ToShortStr(TxTimeout) + ToShortStr(TxOverflowTimeout) + ToShortStr(RxTimeout) + ToShortStr(RxFlushTimeout) + ToShortStr(Heartbeat) + ToIntStr(0));
+ }
+ if (obj.protocol == 2) {
+ // Remote Desktop: Send traffic directly...
+ obj.xxSend(String.fromCharCode(0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00));
+ }
+ // ###BEGIN###{IDER}
+ if (obj.protocol == 3) {
+ // Remote IDER: Send traffic directly...
+ obj.connectstate = 1;
+ obj.xxStateChange(3);
+ }
+ // ###END###{IDER}
+ } else obj.Stop();
+ break;
+ case 0x21: // Response to settings (33)
+ if (obj.amtaccumulator.length < 23) break;
+ cmdsize = 23;
+ obj.xxSend(String.fromCharCode(0x27, 0x00, 0x00, 0x00) + ToIntStr(obj.amtsequence++) + String.fromCharCode(0x00, 0x00, 0x1B, 0x00, 0x00, 0x00));
+ if (obj.protocol == 1) { obj.amtkeepalivetimer = setInterval(obj.xxSendAmtKeepAlive, 2000); }
+ obj.connectstate = 1;
+ obj.xxStateChange(3);
+ break;
+ case 0x29: // Serial Settings (41)
+ if (obj.amtaccumulator.length < 10) break;
+ cmdsize = 10;
+ break;
+ case 0x2A: // Incoming display data (42)
+ if (obj.amtaccumulator.length < 10) break;
+ var cs = (10 + ((obj.amtaccumulator.charCodeAt(9) & 0xFF) << 8) + (obj.amtaccumulator.charCodeAt(8) & 0xFF));
+ if (obj.amtaccumulator.length < cs) break;
+ obj.m.ProcessData(obj.amtaccumulator.substring(10, cs));
+ cmdsize = cs;
+ break;
+ case 0x2B: // Keep alive message (43)
+ if (obj.amtaccumulator.length < 8) break;
+ cmdsize = 8;
+ break;
+ case 0x41:
+ if (obj.amtaccumulator.length < 8) break;
+ obj.connectstate = 1;
+ obj.m.Start();
+ // KVM traffic, forward rest of accumulator directly.
+ if (obj.amtaccumulator.length > 8) { obj.m.ProcessData(obj.amtaccumulator.substring(8)); }
+ cmdsize = obj.amtaccumulator.length;
+ break;
+ default:
+ console.log("Unknown Intel AMT command: " + obj.amtaccumulator.charCodeAt(0) + " acclen=" + obj.amtaccumulator.length);
+ obj.Stop();
+ return;
+ }
+ if (cmdsize == 0) return;
+ obj.amtaccumulator = obj.amtaccumulator.substring(cmdsize);
+ }
+ }
+
+ obj.xxSend = function (x) {
+ if (urlvars && urlvars['redirtrace']) { console.log('REDIR-SEND(' + x.length + '): ' + rstr2hex(x)); }
+ //obj.Debug("Send(" + x.length + "): " + rstr2hex(x));
+ obj.socket.write(new Buffer(x, 'binary'));
+ }
+
+ obj.Send = function (x) {
+ if (obj.socket == null || obj.connectstate != 1) return;
+ if (obj.protocol == 1) { obj.xxSend(String.fromCharCode(0x28, 0x00, 0x00, 0x00) + ToIntStr(obj.amtsequence++) + ToShortStr(x.length) + x); } else { obj.xxSend(x); }
+ }
+
+ obj.xxSendAmtKeepAlive = function () {
+ if (obj.socket == null) return;
+ obj.xxSend(String.fromCharCode(0x2B, 0x00, 0x00, 0x00) + ToIntStr(obj.amtsequence++));
+ }
+
+ obj.xxRandomValueHex = function(len) { return obj.crypto.randomBytes(Math.ceil(len / 2)).toString('hex').slice(0, len); }
+
+ obj.xxOnSocketClosed = function () {
+ if (urlvars && urlvars['redirtrace']) { console.log('REDIR-CLOSED'); }
+ //obj.Debug("Socket Closed");
+ obj.Stop();
+ }
+
+ obj.xxStateChange = function(newstate) {
+ if (obj.State == newstate) return;
+ obj.State = newstate;
+ obj.m.xxStateChange(obj.State);
+ if (obj.onStateChanged != null) obj.onStateChanged(obj, obj.State);
+ }
+
+ obj.Stop = function () {
+ if (urlvars && urlvars['redirtrace']) { console.log('REDIR-CLOSED'); }
+ //obj.Debug("Socket Stopped");
+ obj.xxStateChange(0);
+ obj.connectstate = -1;
+ obj.amtaccumulator = '';
+ if (obj.socket != null) { obj.socket.destroy(); obj.socket = null; }
+ if (obj.amtkeepalivetimer != null) { clearInterval(obj.amtkeepalivetimer); obj.amtkeepalivetimer = null; }
+ }
+
+ obj.RedirectStartSol = String.fromCharCode(0x10, 0x00, 0x00, 0x00, 0x53, 0x4F, 0x4C, 0x20);
+ obj.RedirectStartKvm = String.fromCharCode(0x10, 0x01, 0x00, 0x00, 0x4b, 0x56, 0x4d, 0x52);
+ obj.RedirectStartIder = String.fromCharCode(0x10, 0x00, 0x00, 0x00, 0x49, 0x44, 0x45, 0x52);
+
+ return obj;
+}
+
+function ToIntStr(v) { return String.fromCharCode((v & 0xFF), ((v >> 8) & 0xFF), ((v >> 16) & 0xFF), ((v >> 24) & 0xFF)); }
+function ToShortStr(v) { return String.fromCharCode((v & 0xFF), ((v >> 8) & 0xFF)); }
diff --git a/amt-redir-ws-0.1.0.js b/amt-redir-ws-0.1.0.js
new file mode 100644
index 0000000..9d13596
--- /dev/null
+++ b/amt-redir-ws-0.1.0.js
@@ -0,0 +1,335 @@
+/**
+* @description Intel AMT Redirection Transport Module - using websocket relay
+* @author Ylian Saint-Hilaire
+* @version v0.0.1f
+*/
+
+// Construct a MeshServer object
+var CreateAmtRedirect = function (module) {
+ var obj = {};
+ obj.m = module; // This is the inner module (Terminal or Desktop)
+ module.parent = obj;
+ obj.State = 0;
+ obj.socket = null;
+ // ###BEGIN###{!Mode-Firmware}
+ obj.host = null;
+ obj.port = 0;
+ obj.user = null;
+ obj.pass = null;
+ obj.authuri = '/RedirectionService';
+ obj.tlsv1only = 0;
+ // ###END###{!Mode-Firmware}
+ obj.connectstate = 0;
+ obj.protocol = module.protocol; // 1 = SOL, 2 = KVM, 3 = IDER
+
+ obj.amtaccumulator = '';
+ obj.amtsequence = 1;
+ obj.amtkeepalivetimer = null;
+ obj.digestRealmMatch = null;
+
+ obj.onStateChanged = null;
+
+ // Private method
+ //obj.Debug = function (msg) { console.log(msg); }
+
+ // ###BEGIN###{!Mode-Firmware}
+ obj.Start = function (host, port, user, pass, tls) {
+ obj.host = host;
+ obj.port = port;
+ obj.user = user;
+ obj.pass = pass;
+ obj.connectstate = 0;
+ obj.socket = new WebSocket(window.location.protocol.replace('http', 'ws') + '//' + window.location.host + window.location.pathname.substring(0, window.location.pathname.lastIndexOf('/')) + '/webrelay.ashx?p=2&host=' + host + '&port=' + port + '&tls=' + tls + ((user == '*') ? '&serverauth=1' : '') + ((typeof pass === 'undefined') ? ('&serverauth=1&user=' + user) : '') + '&tls1only=' + obj.tlsv1only); // The "p=2" indicates to the relay that this is a REDIRECTION session
+ obj.socket.onopen = obj.xxOnSocketConnected;
+ obj.socket.onmessage = obj.xxOnMessage;
+ obj.socket.onclose = obj.xxOnSocketClosed;
+ obj.xxStateChange(1);
+ }
+ // ###END###{!Mode-Firmware}
+
+ // ###BEGIN###{Mode-Firmware}
+ obj.Start = function () {
+ obj.connectstate = 0;
+ obj.socket = new WebSocket(window.location.protocol.replace('http', 'ws') + '//' + window.location.host + '/ws-redirection');
+ obj.socket.onopen = obj.xxOnSocketConnected;
+ obj.socket.onmessage = obj.xxOnMessage;
+ obj.socket.onclose = obj.xxOnSocketClosed;
+ obj.xxStateChange(1);
+ }
+ // ###END###{Mode-Firmware}
+
+ obj.xxOnSocketConnected = function() {
+ if (urlvars && urlvars['redirtrace']) console.log('REDIR-CONNECT');
+ obj.xxStateChange(2);
+ if (obj.protocol == 1) obj.xxSend(obj.RedirectStartSol); // TODO: Put these strings in higher level module to tighten code
+ if (obj.protocol == 2) obj.xxSend(obj.RedirectStartKvm); // Don't need these is the feature is not compiled-in.
+ if (obj.protocol == 3) obj.xxSend(obj.RedirectStartIder);
+ }
+
+ // Setup the file reader
+ var fileReader = new FileReader();
+ var fileReaderInuse = false, fileReaderAcc = [];
+ if (fileReader.readAsBinaryString) {
+ // Chrome & Firefox (Draft)
+ fileReader.onload = function (e) { obj.xxOnSocketData(e.target.result); if (fileReaderAcc.length == 0) { fileReaderInuse = false; } else { fileReader.readAsBinaryString(new Blob([fileReaderAcc.shift()])); } }
+ } else if (fileReader.readAsArrayBuffer) {
+ // Chrome & Firefox (Spec)
+ fileReader.onloadend = function (e) { obj.xxOnSocketData(e.target.result); if (fileReaderAcc.length == 0) { fileReaderInuse = false; } else { fileReader.readAsArrayBuffer(fileReaderAcc.shift()); } }
+ }
+
+ obj.xxOnMessage = function (e) {
+ //if (obj.debugmode == 1) { console.log('Recv', e.data); }
+ obj.inDataCount++;
+ if (typeof e.data == 'object') {
+ if (fileReaderInuse == true) { fileReaderAcc.push(e.data); return; }
+ if (fileReader.readAsBinaryString) {
+ // Chrome & Firefox (Draft)
+ fileReaderInuse = true;
+ fileReader.readAsBinaryString(new Blob([e.data]));
+ } else if (fileReader.readAsArrayBuffer) {
+ // Chrome & Firefox (Spec)
+ fileReaderInuse = true;
+ fileReader.readAsArrayBuffer(e.data);
+ } else {
+ // IE10, readAsBinaryString does not exist, use an alternative.
+ var binary = "", bytes = new Uint8Array(e.data), length = bytes.byteLength;
+ for (var i = 0; i < length; i++) { binary += String.fromCharCode(bytes[i]); }
+ obj.xxOnSocketData(binary);
+ }
+ } else {
+ // If we get a string object, it maybe the WebRTC confirm. Ignore it.
+ // obj.debug("MeshDataChannel - OnData - " + typeof e.data + " - " + e.data.length);
+ obj.xxOnSocketData(e.data);
+ }
+ };
+
+ obj.xxOnSocketData = function (data) {
+ if (!data || obj.connectstate == -1) return;
+
+ if (typeof data === 'object') {
+ // This is an ArrayBuffer, convert it to a string array (used in IE)
+ var binary = "";
+ var bytes = new Uint8Array(data);
+ var length = bytes.byteLength;
+ for (var i = 0; i < length; i++) { binary += String.fromCharCode(bytes[i]); }
+ data = binary;
+ }
+ else if (typeof data !== 'string') { return; }
+
+ if ((obj.protocol == 2 || obj.protocol == 3) && obj.connectstate == 1) { return obj.m.ProcessData(data); } // KVM traffic, forward it directly.
+ obj.amtaccumulator += data;
+ if (urlvars && urlvars['redirtrace']) console.log("REDIR-RECV(" + obj.amtaccumulator.length + "): " + rstr2hex(obj.amtaccumulator));
+ while (obj.amtaccumulator.length >= 1) {
+ var cmdsize = 0;
+ switch (obj.amtaccumulator.charCodeAt(0)) {
+ case 0x11: // StartRedirectionSessionReply (17)
+ if (obj.amtaccumulator.length < 4) return;
+ var statuscode = obj.amtaccumulator.charCodeAt(1);
+ switch (statuscode) {
+ case 0: // STATUS_SUCCESS
+ if (obj.amtaccumulator.length < 13) return;
+ var oemlen = obj.amtaccumulator.charCodeAt(12);
+ if (obj.amtaccumulator.length < 13 + oemlen) return;
+ // ###BEGIN###{!Mode-Firmware}
+ // Query for available authentication
+ obj.xxSend(String.fromCharCode(0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00)); // Query authentication support
+ // ###END###{!Mode-Firmware}
+ // ###BEGIN###{Mode-Firmware}
+ // When using websocket, we are already authenticated. Send empty basic auth.
+ obj.xxSend(String.fromCharCode(0x13, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00));
+ // ###END###{Mode-Firmware}
+ cmdsize = (13 + oemlen);
+ break;
+ default:
+ obj.Stop();
+ break;
+ }
+ break;
+ case 0x14: // AuthenticateSessionReply (20)
+ if (obj.amtaccumulator.length < 9) return;
+ var authDataLen = ReadIntX(obj.amtaccumulator, 5);
+ if (obj.amtaccumulator.length < 9 + authDataLen) return;
+ var status = obj.amtaccumulator.charCodeAt(1);
+ var authType = obj.amtaccumulator.charCodeAt(4);
+ var authData = [];
+ for (i = 0; i < authDataLen; i++) { authData.push(obj.amtaccumulator.charCodeAt(9 + i)); }
+ var authDataBuf = obj.amtaccumulator.substring(9, 9 + authDataLen);
+ cmdsize = 9 + authDataLen;
+ // ###BEGIN###{!Mode-Firmware}
+ if (authType == 0) {
+ // Query
+ if (authData.indexOf(4) >= 0) {
+ // Good Digest Auth (With cnonce and all)
+ obj.xxSend(String.fromCharCode(0x13, 0x00, 0x00, 0x00, 0x04) + IntToStrX(obj.user.length + obj.authuri.length + 8) + String.fromCharCode(obj.user.length) + obj.user + String.fromCharCode(0x00, 0x00) + String.fromCharCode(obj.authuri.length) + obj.authuri + String.fromCharCode(0x00, 0x00, 0x00, 0x00));
+ }
+ else if (authData.indexOf(3) >= 0) {
+ // Bad Digest Auth (Not sure why this is supported, cnonce is not used!)
+ obj.xxSend(String.fromCharCode(0x13, 0x00, 0x00, 0x00, 0x03) + IntToStrX(obj.user.length + obj.authuri.length + 7) + String.fromCharCode(obj.user.length) + obj.user + String.fromCharCode(0x00, 0x00) + String.fromCharCode(obj.authuri.length) + obj.authuri + String.fromCharCode(0x00, 0x00, 0x00));
+ }
+ else if (authData.indexOf(1) >= 0) {
+ // Basic Auth (Probably a good idea to not support this unless this is an old version of Intel AMT)
+ obj.xxSend(String.fromCharCode(0x13, 0x00, 0x00, 0x00, 0x01) + IntToStrX(obj.user.length + obj.pass.length + 2) + String.fromCharCode(obj.user.length) + obj.user + String.fromCharCode(obj.pass.length) + obj.pass);
+ }
+ else obj.Stop();
+ }
+ else if ((authType == 3 || authType == 4) && status == 1) {
+ var curptr = 0;
+
+ // Realm
+ var realmlen = authDataBuf.charCodeAt(curptr);
+ var realm = authDataBuf.substring(curptr + 1, curptr + 1 + realmlen);
+ curptr += (realmlen + 1);
+
+ // Check the digest realm. If it does not match, close the connection.
+ if (obj.digestRealmMatch && (obj.digestRealmMatch != realm)) { obj.Stop(); return; }
+
+ // Nonce
+ var noncelen = authDataBuf.charCodeAt(curptr);
+ var nonce = authDataBuf.substring(curptr + 1, curptr + 1 + noncelen);
+ curptr += (noncelen + 1);
+
+ // QOP
+ var qoplen = 0;
+ var qop = null;
+ var cnonce = obj.xxRandomNonce(32);
+ var snc = '00000002';
+ var extra = '';
+ if (authType == 4) {
+ qoplen = authDataBuf.charCodeAt(curptr);
+ qop = authDataBuf.substring(curptr + 1, curptr + 1 + qoplen);
+ curptr += (qoplen + 1);
+ extra = snc + ':' + cnonce + ':' + qop + ':';
+ }
+
+ var digest = hex_md5(hex_md5(obj.user + ':' + realm + ':' + obj.pass) + ':' + nonce + ':' + extra + hex_md5('POST:' + obj.authuri));
+ var totallen = obj.user.length + realm.length + nonce.length + obj.authuri.length + cnonce.length + snc.length + digest.length + 7;
+ if (authType == 4) totallen += (qop.length + 1);
+ var buf = String.fromCharCode(0x13, 0x00, 0x00, 0x00, authType) + IntToStrX(totallen) + String.fromCharCode(obj.user.length) + obj.user + String.fromCharCode(realm.length) + realm + String.fromCharCode(nonce.length) + nonce + String.fromCharCode(obj.authuri.length) + obj.authuri + String.fromCharCode(cnonce.length) + cnonce + String.fromCharCode(snc.length) + snc + String.fromCharCode(digest.length) + digest;
+ if (authType == 4) buf += (String.fromCharCode(qop.length) + qop);
+ obj.xxSend(buf);
+ }
+ else
+ // ###END###{!Mode-Firmware}
+ if (status == 0) { // Success
+ if (obj.protocol == 1) {
+ // Serial-over-LAN: Send Intel AMT serial settings...
+ var MaxTxBuffer = 10000;
+ var TxTimeout = 100;
+ var TxOverflowTimeout = 0;
+ var RxTimeout = 10000;
+ var RxFlushTimeout = 100;
+ var Heartbeat = 0;//5000;
+ obj.xxSend(String.fromCharCode(0x20, 0x00, 0x00, 0x00) + IntToStrX(obj.amtsequence++) + ShortToStrX(MaxTxBuffer) + ShortToStrX(TxTimeout) + ShortToStrX(TxOverflowTimeout) + ShortToStrX(RxTimeout) + ShortToStrX(RxFlushTimeout) + ShortToStrX(Heartbeat) + IntToStrX(0));
+ }
+ if (obj.protocol == 2) {
+ // Remote Desktop: Send traffic directly...
+ obj.xxSend(String.fromCharCode(0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00));
+ }
+ if (obj.protocol == 3) {
+ // Remote IDER: Send traffic directly...
+ obj.connectstate = 1;
+ obj.xxStateChange(3);
+ }
+ } else obj.Stop();
+ break;
+ case 0x21: // Response to settings (33)
+ if (obj.amtaccumulator.length < 23) break;
+ cmdsize = 23;
+ obj.xxSend(String.fromCharCode(0x27, 0x00, 0x00, 0x00) + IntToStrX(obj.amtsequence++) + String.fromCharCode(0x00, 0x00, 0x1B, 0x00, 0x00, 0x00));
+ if (obj.protocol == 1) { obj.amtkeepalivetimer = setInterval(obj.xxSendAmtKeepAlive, 2000); }
+ obj.connectstate = 1;
+ obj.xxStateChange(3);
+ break;
+ case 0x29: // Serial Settings (41)
+ if (obj.amtaccumulator.length < 10) break;
+ cmdsize = 10;
+ break;
+ case 0x2A: // Incoming display data (42)
+ if (obj.amtaccumulator.length < 10) break;
+ var cs = (10 + ((obj.amtaccumulator.charCodeAt(9) & 0xFF) << 8) + (obj.amtaccumulator.charCodeAt(8) & 0xFF));
+ if (obj.amtaccumulator.length < cs) break;
+ obj.m.ProcessData(obj.amtaccumulator.substring(10, cs));
+ cmdsize = cs;
+ break;
+ case 0x2B: // Keep alive message (43)
+ if (obj.amtaccumulator.length < 8) break;
+ cmdsize = 8;
+ break;
+ case 0x41:
+ if (obj.amtaccumulator.length < 8) break;
+ obj.connectstate = 1;
+ obj.m.Start();
+ // KVM traffic, forward rest of accumulator directly.
+ if (obj.amtaccumulator.length > 8) { obj.m.ProcessData(obj.amtaccumulator.substring(8)); }
+ cmdsize = obj.amtaccumulator.length;
+ break;
+ case 0xF0:
+ // console.log('Session is being recorded');
+ obj.serverIsRecording = true;
+ cmdsize = 1;
+ break;
+ default:
+ console.log("Unknown Intel AMT command: " + obj.amtaccumulator.charCodeAt(0) + " acclen=" + obj.amtaccumulator.length);
+ obj.Stop();
+ return;
+ }
+ if (cmdsize == 0) return;
+ obj.amtaccumulator = obj.amtaccumulator.substring(cmdsize);
+ }
+ }
+
+ obj.xxSend = function (x) {
+ if (urlvars && urlvars['redirtrace']) { console.log('REDIR-SEND(' + x.length + '): ' + rstr2hex(x)); }
+ //obj.Debug("Redir Send(" + x.length + "): " + rstr2hex(x));
+ if (obj.socket != null && obj.socket.readyState == WebSocket.OPEN) {
+ var b = new Uint8Array(x.length);
+ for (var i = 0; i < x.length; ++i) { b[i] = x.charCodeAt(i); }
+ obj.socket.send(b.buffer);
+ }
+ }
+
+ obj.Send = function (x) {
+ if (obj.socket == null || obj.connectstate != 1) return;
+ if (obj.protocol == 1) { obj.xxSend(String.fromCharCode(0x28, 0x00, 0x00, 0x00) + IntToStrX(obj.amtsequence++) + ShortToStrX(x.length) + x); } else { obj.xxSend(x); }
+ }
+
+ obj.xxSendAmtKeepAlive = function () {
+ if (obj.socket == null) return;
+ obj.xxSend(String.fromCharCode(0x2B, 0x00, 0x00, 0x00) + IntToStrX(obj.amtsequence++));
+ }
+
+ obj.xxRandomNonceX = 'abcdef0123456789';
+ obj.xxRandomNonce = function (length) {
+ var r = "";
+ for (var i = 0; i < length; i++) { r += obj.xxRandomNonceX.charAt(Math.floor(Math.random() * obj.xxRandomNonceX.length)); }
+ return r;
+ }
+
+ obj.xxOnSocketClosed = function () {
+ if (urlvars && urlvars['redirtrace']) { console.log('REDIR-CLOSED'); }
+ //obj.Debug("Redir Socket Closed");
+ obj.Stop();
+ }
+
+ obj.xxStateChange = function(newstate) {
+ if (obj.State == newstate) return;
+ obj.State = newstate;
+ obj.m.xxStateChange(obj.State);
+ if (obj.onStateChanged != null) obj.onStateChanged(obj, obj.State);
+ }
+
+ obj.Stop = function () {
+ //obj.Debug("Redir Socket Stopped");
+ obj.xxStateChange(0);
+ obj.connectstate = -1;
+ obj.amtaccumulator = "";
+ if (obj.socket != null) { obj.socket.close(); obj.socket = null; }
+ if (obj.amtkeepalivetimer != null) { clearInterval(obj.amtkeepalivetimer); obj.amtkeepalivetimer = null; }
+ }
+
+ obj.RedirectStartSol = String.fromCharCode(0x10, 0x00, 0x00, 0x00, 0x53, 0x4F, 0x4C, 0x20);
+ obj.RedirectStartKvm = String.fromCharCode(0x10, 0x01, 0x00, 0x00, 0x4b, 0x56, 0x4d, 0x52);
+ obj.RedirectStartIder = String.fromCharCode(0x10, 0x00, 0x00, 0x00, 0x49, 0x44, 0x45, 0x52);
+
+ return obj;
+}
diff --git a/amt-scanner-0.1.0.js b/amt-scanner-0.1.0.js
new file mode 100644
index 0000000..1090b73
--- /dev/null
+++ b/amt-scanner-0.1.0.js
@@ -0,0 +1,235 @@
+/**
+* @description Meshcentral Intel AMT Local Scanner
+* @author Ylian Saint-Hilaire
+* @version v0.0.1
+*/
+
+// Construct a Intel AMT Scanner object
+var CreateAmtScanner = function (func) {
+ var obj = {};
+ obj.active = false;
+ obj.dgram = require('dgram');
+ obj.servers = {};
+ obj.rserver = {};
+ obj.rpacket = null;
+ obj.tagToId = {}; // Tag --> { lastpong: time, id: NodeId }
+ obj.scanTable = {}; // Handle --> ScanInfo : { lastping: time, lastpong: time, nodeinfo:{node} }
+ obj.scanTableTags = {}; // Tag --> ScanInfo
+ obj.pendingSends = []; // We was to stagger the sends using a 10ms timer
+ obj.pendingSendTimer = null;
+ obj.mainTimer = null;
+ obj.nextTag = 0;
+ obj.computerPresenceFunc = func;
+ var PeriodicScanTime = 30000; // Interval between scan sweeps
+ var PeriodicScanTimeout = 65000; // After this time, timeout the device.
+
+ // Build a RMCP packet with a given tag field
+ obj.buildRmcpPing = function (tag) {
+ var packet = new Buffer(hex2rstr('06000006000011BE80000000'), 'ascii');
+ packet[9] = tag;
+ return packet;
+ }
+
+ // Start scanning for local network Intel AMT computers
+ obj.start = function () {
+ if (obj.active == false) {
+ obj.active = true;
+ obj.performScan();
+ obj.mainTimer = setInterval(obj.performScan, PeriodicScanTime);
+ }
+ }
+
+ // Stop scanning for local network Intel AMT computers
+ obj.stop = function () {
+ obj.active = false;
+ for (var i in obj.servers) { obj.servers[i].close(); } // Stop all servers
+ obj.servers = {};
+ if (obj.mainTimer != null) { clearInterval(obj.mainTimer); obj.mainTimer = null; }
+ }
+
+ // Scan for Intel AMT computers using network multicast
+ obj.performRangeScan = function (id, rangestr, func) {
+ if (obj.rpacket == null) { obj.rpacket = obj.buildRmcpPing(0); }
+ var range = obj.parseIpv4Range(rangestr);
+ //console.log(obj.IPv4NumToStr(range.min), obj.IPv4NumToStr(range.max));
+ if (range == null || (range.min > range.max)) return false;
+ var rangeinfo = { id: id, range: rangestr, min: range.min, max: range.max, results: {}, resultCount: 0 };
+ obj.rserver[id] = rangeinfo;
+ rangeinfo.server = obj.dgram.createSocket("udp4");
+ rangeinfo.server.bind(0);
+ rangeinfo.server.on('error', function(err) { console.log(err); });
+ rangeinfo.server.on('message', function(data, rinfo) { obj.parseRmcpPacket(data, rinfo, 0, func, rangeinfo); });
+ rangeinfo.server.on('listening', function () {
+ for (var i = rangeinfo.min; i <= rangeinfo.max; i++) {
+ rangeinfo.server.send(obj.rpacket, 0, obj.rpacket.length, 623, obj.IPv4NumToStr(i));
+ rangeinfo.server.send(obj.rpacket, 0, obj.rpacket.length, 623, obj.IPv4NumToStr(i));
+ }
+ });
+ rangeinfo.timer = setTimeout(function () {
+ if (rangeinfo.resultCount == 0) { func(obj, null); }
+ rangeinfo.server.close();
+ delete rangeinfo.server;
+ delete rangeinfo;
+ }, 5000);
+ return true;
+ }
+
+ // Parse range, used to parse "ip", "ip/mask" or "ip-ip" notation.
+ // Return the start and end value of the scan
+ obj.parseIpv4Range = function (range) {
+ if (range == undefined || range == null) return null;
+ var x = range.split('-');
+ if (x.length == 2) { return { min: obj.parseIpv4Addr(x[0]), max: obj.parseIpv4Addr(x[1]) }; }
+ x = range.split('/');
+ if (x.length == 2) {
+ var ip = obj.parseIpv4Addr(x[0]), masknum = parseInt(x[1]), mask = 0;
+ if (masknum < 16) return null;
+ for (var i = 0; i < (32 - masknum) ; i++) { mask = (mask << 1); mask++; }
+ return { min: ip & (0xFFFFFFFF - mask), max: (ip & (0xFFFFFFFF - mask)) + mask };
+ }
+ x = obj.parseIpv4Addr(range);
+ if (x == null) return null;
+ return { min: x, max: x };
+ }
+
+ // Parse IP address. Takes a
+ obj.parseIpv4Addr = function (addr) {
+ var x = addr.split('.');
+ if (x.length == 4) { return (parseInt(x[0]) << 24) + (parseInt(x[1]) << 16) + (parseInt(x[2]) << 8) + (parseInt(x[3]) << 0); }
+ return null;
+ }
+
+ // IP address number to string
+ obj.IPv4NumToStr = function (num) {
+ return ((num >> 24) & 0xFF) + '.' + ((num >> 16) & 0xFF) + '.' + ((num >> 8) & 0xFF) + '.' + (num & 0xFF);
+ }
+
+ // Scan the list of all computers
+ obj.performScan = function () {
+ if (obj.active == false || computerlist == undefined) return;
+ for (var i in obj.scanTable) { obj.scanTable[i].present = false; }
+ if (computerlist.length > 0) {
+ for (var i in computerlist) {
+ var computer = computerlist[i];
+ var host = computer.host.toLowerCase();
+ if ((host != '127.0.0.1') && (host != '::1') && (host != 'localhost') && (host.split(':').length == 1)) {
+ var scaninfo = obj.scanTable[computer.h];
+ if (scaninfo == undefined) {
+ var tag = obj.nextTag++;
+ obj.scanTableTags[tag] = obj.scanTable[computer.h] = scaninfo = { computer: computer, present: true, tag: tag, scanstate: -1, lastpong: Date.now() };
+ } else {
+ scaninfo.present = true;
+ var delta = Date.now() - scaninfo.lastpong;
+ if ((delta > PeriodicScanTimeout) && (scaninfo.scanstate != 0)) { // More than the timeout without a response, mark the node as unknown state
+ scaninfo.scanstate = 0;
+ if (obj.computerPresenceFunc) { obj.computerPresenceFunc(scaninfo.computer.h, false); }
+ }
+ }
+ // Start scanning this node
+ scaninfo.lastping = Date.now();
+ obj.checkAmtPresence(computer.host, scaninfo.tag);
+ }
+ }
+ }
+ for (var i in obj.scanTable) {
+ if (obj.scanTable[i].present == false) {
+ // Stop scanning this node
+ delete obj.scanTableTags[obj.scanTable[i].tag];
+ delete obj.scanTable[i];
+ }
+ }
+ }
+
+ // Check the presense of a specific Intel AMT computer
+ obj.checkAmtPresence = function (host, tag) {
+ var serverid = Math.floor(tag / 255);
+ var servertag = (tag % 255);
+ var packet = obj.buildRmcpPing(servertag);
+ var server = obj.servers[serverid];
+ if (server == undefined) {
+ // Start new server
+ server = obj.dgram.createSocket('udp4');
+ server.on('error', function(err) { });
+ server.on('message', function (data, rinfo) { obj.parseRmcpPacket(data, rinfo, serverid, obj.changeConnectState, null); });
+ server.on('listening', function() { obj.pendingSends.push([ server, packet, host ]); if (obj.pendingSendTimer == null) { obj.pendingSendTimer = setInterval(obj.sendPendingPacket, 10); } });
+ server.bind(0);
+ obj.servers[serverid] = server;
+ } else {
+ // Use existing server
+ obj.pendingSends.push([ server, packet, host ]);
+ if (obj.pendingSendTimer == null) { obj.pendingSendTimer = setInterval(obj.sendPendingPacket, 10); }
+ }
+ }
+
+ // Send a pending RMCP packet
+ obj.sendPendingPacket = function () {
+ try {
+ var p = obj.pendingSends.shift();
+ if (p != undefined) {
+ p[0].send(p[1], 0, p[1].length, 623, p[2]);
+ p[0].send(p[1], 0, p[1].length, 623, p[2]);
+ } else {
+ clearInterval(obj.pendingSendTimer);
+ obj.pendingSendTimer = null;
+ }
+ } catch (e) { }
+ }
+
+ // Parse RMCP packet
+ obj.parseRmcpPacket = function (data, rinfo, serverid, func, rangeinfo) {
+ if (data == null || data.length < 20) return;
+ if (((data[12] == 0) || (data[13] != 0) || (data[14] != 1) || (data[15] != 0x57)) && (data[21] & 32)) {
+ var result = { tag: (serverid * 255) + data[9], ver: ((data[18] >> 4) & 0x0F) + '.' + (data[18] & 0x0F), state: (data[19] & 0x03), port: ((data[16] * 256) + data[17]), dualport: (((data[19] & 0x04) != 0) ? true : false), rinfo: rinfo };
+ result.tls = (((result.openPort == 16993) || (result.dualPorts == true)) ? 1 : 0)
+ if (rangeinfo != null) {
+ if ((result.state <= 2) && (!rangeinfo.results[rinfo.address])) {
+ rangeinfo.results[rinfo.address] = result;
+ rangeinfo.resultCount++;
+ obj.reverseLookup(rinfo.address, function (err, domains) {
+ result.domains = domains;
+ func(obj, result, rangeinfo);
+ });
+ }
+ } else {
+ func(obj, result, rangeinfo);
+ }
+ }
+ }
+
+ // Use the RMCP packet to change the computer state
+ obj.changeConnectState = function (obj, result, rangeinfo) {
+ var scaninfo = obj.scanTableTags[result.tag];
+ if (scaninfo) {
+ scaninfo.lastpong = Date.now();
+ if (scaninfo.scanstate != 1) {
+ scaninfo.scanstate = 1;
+ if (obj.computerPresenceFunc) obj.computerPresenceFunc(scaninfo.computer.h, true);
+ }
+ }
+ }
+
+ // Perform DNS reverse lookup
+ obj.reverseLookup = function(ip, callback) {
+ var callbackCalled = false, timer = null;
+ var doCallback = function (err, domains) {
+ if (err) domains = [ip];
+ if (callbackCalled) return;
+ callbackCalled = true;
+ if (timer != null) {
+ // Cancelling timer to safe few seconds
+ clearTimeout(timer);
+ timer = null;
+ }
+ callback(err, domains);
+ }
+ // throw failed upon timeout
+ timer = setTimeout(function () {
+ timer = null; // Ensure timer is nullified
+ doCallback(new Error("Timeout exceeded"), null);
+ }, 3000);
+
+ require("dns").reverse(ip, doCallback);
+ }
+
+ return obj;
+}
\ No newline at end of file
diff --git a/amt-script-0.2.0.js b/amt-script-0.2.0.js
new file mode 100644
index 0000000..3ebfc70
--- /dev/null
+++ b/amt-script-0.2.0.js
@@ -0,0 +1,440 @@
+/**
+* @fileoverview Script Compiler / Decompiler / Runner
+* @author Ylian Saint-Hilaire
+* @version v0.1.0e
+*/
+
+// Core functions
+script_functionTable1 = ['nop', 'jump', 'set', 'print', 'dialog', 'getitem', 'substr', 'indexof', 'split', 'join', 'length', 'jsonparse', 'jsonstr', 'add', 'substract', 'parseint', 'wsbatchenum', 'wsput', 'wscreate', 'wsdelete', 'wsexec', 'scriptspeed', 'wssubscribe', 'wsunsubscribe', 'readchar', 'signwithdummyca'];
+
+// functions of type ARG1 = func(ARG2, ARG3, ARG4, ARG5, ARG6)
+script_functionTable2 = ['encodeuri', 'decodeuri', 'passwordcheck', 'atob', 'btoa', 'hex2str', 'str2hex', 'random', 'md5', 'maketoarray', 'readshort', 'readshortx', 'readint', 'readsint', 'readintx', 'shorttostr', 'shorttostrx', 'inttostr', 'inttostrx'];
+
+// functions of type ARG1 = func(ARG2, ARG3, ARG4, ARG5, ARG6)
+script_functionTableX2 = [encodeURI, decodeURI, passwordcheck, window.atob.bind(window), window.btoa.bind(window), hex2rstr, rstr2hex, random, rstr_md5, MakeToArray, ReadShort, ReadShortX, ReadInt, ReadSInt, ReadIntX, ShortToStr, ShortToStrX, IntToStr, IntToStrX];
+
+// Optional functions of type ARG1 = func(ARG2, ARG3, ARG4, ARG5, ARG6)
+script_functionTable3 = ['pullsystemstatus', 'pulleventlog', 'pullauditlog', 'pullcertificates', 'pullwatchdog', 'pullsystemdefense', 'pullhardware', 'pulluserinfo', 'pullremoteaccess', 'highlightblock', 'disconnect', 'getsidstring', 'getsidbytearray', 'pulleventsubscriptions'];
+
+// Optional functions of type ARG1 = func(ARG2, ARG3, ARG4, ARG5, ARG6)
+script_functionTableX3 = [
+ PullSystemStatus
+ ,
+ // ###BEGIN###{EventLog}
+ PullEventLog
+ // ###END###{EventLog}
+ ,
+ // ###BEGIN###{AuditLog}
+ PullAuditLog
+ // ###END###{AuditLog}
+ ,
+ // ###BEGIN###{Certificates}
+ PullCertificates
+ // ###END###{Certificates}
+ ,
+ // ###BEGIN###{AgentPresence}
+ PullWatchdog
+ // ###END###{AgentPresence}
+ ,
+ // ###BEGIN###{SystemDefense}
+ PullSystemDefense
+ // ###END###{SystemDefense}
+ ,
+ // ###BEGIN###{HardwareInfo}
+ PullHardware
+ // ###END###{HardwareInfo}
+ ,
+ PullUserInfo
+ ,
+ // ###BEGIN###{RemoteAccess}
+ PullRemoteAccess
+ // ###END###{RemoteAccess}
+ ,
+ // ###BEGIN###{Scripting-Editor}
+ script_HighlightBlock
+ // ###END###{Scripting-Editor}
+ ,
+ // ###BEGIN###{ComputerSelector}
+ disconnect
+ // ###END###{ComputerSelector}
+ ,
+ function (runner, x) { return GetSidString(x); }
+ ,
+ function (runner, x) { return GetSidByteArray(x); }
+ ,
+ // ###BEGIN###{EventSubscriptions}
+ PullEventSubscriptions
+ // ###END###{EventSubscriptions}
+];
+
+// Setup the script state
+function script_setup(binary, startvars) {
+ var obj = { startvars:startvars };
+ if (binary.length < 6) { console.error('Invalid script length'); return null; } // Script must have at least 6 byte header
+ if (ReadInt(binary, 0) != 0x247D2945) { console.error('Invalid binary script'); return null; } // Check the script magic header
+ if (ReadShort(binary, 4) > 1) { console.error('Unsupported script version'); return null; } // Check the script version
+ obj.script = binary.substring(6);
+ // obj.onStep;
+ // obj.onConsole;
+
+ // Reset the script to the start
+ obj.reset = function (stepspeed) {
+ obj.stop();
+ obj.ip = 0;
+ obj.variables = startvars;
+ obj.state = 1;
+ }
+
+ // Start the script
+ obj.start = function (stepspeed) {
+ obj.stop();
+ obj.stepspeed = stepspeed;
+ if (stepspeed > 0) { obj.timer = setInterval(function () { obj.step() }, stepspeed); }
+ }
+
+ // Stop the script
+ obj.stop = function () {
+ if (obj.timer != null) { clearInterval(obj.timer); }
+ obj.timer = null;
+ obj.stepspeed = 0;
+ }
+
+ // function used to load and store variable values
+ obj.getVar = function (name) { if (name == undefined) return undefined; return obj.getVarEx(name.split('.'), obj.variables); }
+ obj.getVarEx = function (name, val) { try { if (name == undefined) return undefined; if (name.length == 0) return val; return obj.getVarEx(name.slice(1), val[name[0]]); } catch (e) { return null; } }
+ obj.setVar = function (name, val) { obj.setVarEx(name.split('.'), obj.variables, val); }
+ obj.setVarEx = function (name, vars, val) { if (name.length == 1) { vars[name[0]] = val; } else { obj.setVarEx(name.slice(1), vars[name[0]], val); } }
+
+ // Run the script one step forward
+ obj.step = function () {
+ if (obj.state != 1) return;
+ if (obj.ip < obj.script.length) {
+ var cmdid = ReadShort(obj.script, obj.ip);
+ var cmdlen = ReadShort(obj.script, obj.ip + 2);
+ var argcount = ReadShort(obj.script, obj.ip + 4);
+ var argptr = obj.ip + 6;
+ var args = [];
+
+ // Clear all temp variables (This is optional)
+ for (var i in obj.variables) { if (i.startsWith('__')) { delete obj.variables[i]; } }
+
+ // Loop on each argument, moving forward by the argument length each time
+ for (var i = 0; i < argcount; i++) {
+ var arglen = ReadShort(obj.script, argptr);
+ var argval = obj.script.substring(argptr + 2, argptr + 2 + arglen);
+ var argtyp = argval.charCodeAt(0);
+ argval = argval.substring(1);
+ if (argtyp < 2) {
+ // Get the value and replace all {var} with variable values
+ while (argval.split("{").length > 1) { var t = argval.split("{").pop().split("}").shift(); argval = argval.replace('{' + t + '}', obj.getVar(t)); }
+ if (argtyp == 1) { obj.variables['__' + i] = decodeURI(argval); argval = '__' + i; } // If argtyp is 1, this is a literal. Store in temp variable.
+ args.push(argval);
+ }
+ if (argtyp == 2 || argtyp == 3) {
+ obj.variables['__' + i] = ReadSInt(argval, 0);
+ args.push('__' + i);
+ }
+ argptr += (2 + arglen);
+ }
+
+ // Move instruction pointer forward by command size
+ obj.ip += cmdlen;
+
+ // Get all variable values
+ var argsval = [];
+ for (var i = 0; i < 10; i++) { argsval.push(obj.getVar(args[i])); }
+ var storeInArg0;
+
+ try {
+ if (cmdid < 10000) {
+ // Lets run the actual command
+ switch (cmdid) {
+ case 0: // nop
+ break;
+ case 1: // jump(label) or jump(label, a, compare, b)
+ if (argsval[2]) {
+ if (
+ (argsval[2] == '<' && argsval[1] < argsval[3]) ||
+ (argsval[2] == '<=' && argsval[1] <= argsval[3]) ||
+ (argsval[2] == '!=' && argsval[1] != argsval[3]) ||
+ (argsval[2] == '=' && argsval[1] == argsval[3]) ||
+ (argsval[2] == '>=' && argsval[1] >= argsval[3]) ||
+ (argsval[2] == '>' && argsval[1] > argsval[3])
+ ) { obj.ip = argsval[0]; }
+ } else {
+ obj.ip = argsval[0]; // Set the instruction pointer to the new location in the script
+ }
+ break;
+ case 2: // set(variable, value)
+ if (args[1] == undefined) delete obj.variables[args[0]]; else obj.setVar(args[0], argsval[1]);
+ break;
+ case 3: // print(message)
+ if (obj.onConsole) { obj.onConsole(obj.toString(argsval[0]), obj); } else { console.log(obj.toString(argsval[0])); }
+ // Q(obj.consoleid).value += () + '\n'); Q(obj.console).scrollTop = Q(obj.console).scrollHeight;
+ break;
+ case 4: // dialog(title, content, buttons)
+ obj.state = 2;
+ obj.dialog = true;
+ setDialogMode(11, argsval[0], argsval[2], obj.xxStepDialogOk, argsval[1], obj);
+ break;
+ case 5: // getitem(a, b, c)
+ for (var i in argsval[1]) { if (argsval[1][i][argsval[2]] == argsval[3]) { storeInArg0 = i; } };
+ break;
+ case 6: // substr(variable_dest, variable_src, index, len)
+ storeInArg0 = argsval[1].substr(argsval[2], argsval[3]);
+ break;
+ case 7: // indexOf(variable_dest, variable_src, index, len)
+ storeInArg0 = argsval[1].indexOf(argsval[2]);
+ break;
+ case 8: // split(variable_dest, variable_src, separator)
+ storeInArg0 = argsval[1].split(argsval[2]);
+ break;
+ case 9: // join(variable_dest, variable_src, separator)
+ storeInArg0 = argsval[1].join(argsval[2]);
+ break;
+ case 10: // length(variable_dest, variable_src)
+ storeInArg0 = argsval[1].length;
+ break;
+ case 11: // jsonparse(variable_dest, json)
+ storeInArg0 = JSON.parse(argsval[1]);
+ break;
+ case 12: // jsonstr(variable_dest, variable_src)
+ storeInArg0 = JSON.stringify(argsval[1]);
+ break;
+ case 13: // add(variable_dest, variable_src, value)
+ storeInArg0 = (argsval[1] + argsval[2]);
+ break;
+ case 14: // substract(variable_dest, variable_src, value)
+ storeInArg0 = (argsval[1] - argsval[2]);
+ break;
+ case 15: // parseInt(variable_dest, variable_src)
+ storeInArg0 = parseInt(argsval[1]);
+ break;
+ case 16: // wsbatchenum(name, objectList)
+ obj.state = 2;
+ obj.amtstack.BatchEnum(argsval[0], argsval[1], obj.xxWsmanReturn, obj);
+ break;
+ case 17: // wsput(name, args)
+ obj.state = 2;
+ obj.amtstack.Put(argsval[0], argsval[1], obj.xxWsmanReturn, obj);
+ break;
+ case 18: // wscreate(name, args)
+ obj.state = 2;
+ obj.amtstack.Create(argsval[0], argsval[1], obj.xxWsmanReturn, obj);
+ break;
+ case 19: // wsdelete(name, args)
+ obj.state = 2;
+ obj.amtstack.Delete(argsval[0], argsval[1], obj.xxWsmanReturn, obj);
+ break;
+ case 20: // wsexec(name, method, args, selectors)
+ obj.state = 2;
+ obj.amtstack.Exec(argsval[0], argsval[1], argsval[2], obj.xxWsmanReturn, obj, 0, argsval[3]);
+ break;
+ case 21: // Script Speed
+ obj.stepspeed = argsval[0];
+ if (obj.timer != null) { clearInterval(obj.timer); obj.timer = setInterval(function () { obj.step() }, obj.stepspeed); }
+ break;
+ case 22: // wssubscribe(name, delivery, url, selectors, opaque, user, pass)
+ obj.state = 2;
+ obj.amtstack.Subscribe(argsval[0], argsval[1], argsval[2], obj.xxWsmanReturn, obj, 0, argsval[3], argsval[4], argsval[5], argsval[6]);
+ break;
+ case 23: // wsunsubscribe(name, selectors)
+ obj.state = 2;
+ obj.amtstack.UnSubscribe(argsval[0], obj.xxWsmanReturn, obj, 0, argsval[1]);
+ break;
+ case 24: // readchar(str, pos)
+ console.log(argsval[1], argsval[2], argsval[1].charCodeAt(argsval[2]));
+ storeInArg0 = argsval[1].charCodeAt(argsval[2]);
+ break;
+ case 25: // signWithDummyCa
+ // ###BEGIN###{Certificates}
+ obj.state = 2;
+ // DERKey, xxCaPrivateKey, certattributes, issuerattributes
+ amtcert_signWithCaKey(argsval[0], null, argsval[1], { 'CN': 'Untrusted Root Certificate' }, obj.xxSignWithDummyCaReturn);
+ // ###END###{Certificates}
+ break;
+ default: {
+ obj.state = 9;
+ console.error("Script Error, unknown command: " + cmdid);
+ }
+ }
+ } else {
+ if (cmdid < 20000) {
+ // functions of type ARG1 = func(ARG2, ARG3, ARG4, ARG5, ARG6)
+ storeInArg0 = script_functionTableX2[cmdid - 10000](argsval[1], argsval[2], argsval[3], argsval[4], argsval[5], argsval[6]);
+ } else {
+ // Optional functions of type ARG1 = func(ARG2, ARG3, ARG4, ARG5, ARG6)
+ if (script_functionTableX3 && script_functionTableX3[cmdid - 20000]) {
+ storeInArg0 = script_functionTableX3[cmdid - 20000](obj, argsval[1], argsval[2], argsval[3], argsval[4], argsval[5], argsval[6]); // Note that optional calls start with "obj" as first argument.
+ }
+ }
+ }
+
+ if (storeInArg0 != undefined) obj.setVar(args[0], storeInArg0);
+ } catch (e) {
+ if (typeof e == 'object') { e = e.message; }
+ obj.setVar('_exception', e);
+ }
+ }
+
+ if (obj.state == 1 && obj.ip >= obj.script.length) { obj.state = 0; obj.stop(); }
+ if (obj.onStep) obj.onStep(obj);
+ return obj;
+ }
+
+ obj.xxStepDialogOk = function (button) {
+ obj.variables['DialogSelect'] = button;
+ obj.state = 1;
+ obj.dialog = false;
+ if (obj.onStep) obj.onStep(obj);
+ }
+
+ // ###BEGIN###{**ClosureAdvancedMode}
+ obj.xxWsmanReturnFix = function (x) {
+ if (!x || x == null) return;
+ if (x.Header) { x['Header'] = x.Header; delete x.Header; }
+ if (x.Body) { x['Body'] = x.Body; delete x.Body; }
+ if (x.Responses) { x['Responses'] = x.Responses; delete x.Responses; }
+ if (x.Response) { x['Response'] = x.Response; delete x.Response; }
+ if (x.ReturnValueStr) { x['ReturnValueStr'] = x.ReturnValueStr; delete x.ReturnValueStr; }
+ }
+ // ###END###{**ClosureAdvancedMode}
+
+ obj.xxWsmanReturn = function (stack, name, responses, status) {
+ // ###BEGIN###{**ClosureAdvancedMode}
+ // This is required when Google Closure is used
+ if (responses) {
+ obj.xxWsmanReturnFix(responses);
+ for (var i in responses) {
+ obj.xxWsmanReturnFix(responses[i]);
+ for (var j in responses[i]) { obj.xxWsmanReturnFix(responses[i][j]); }
+ }
+ }
+ // ###END###{**ClosureAdvancedMode}
+ obj.setVar(name, responses);
+ obj.setVar('wsman_result', status);
+ obj.setVar('wsman_result_str', ((httpErrorTable[status]) ? (httpErrorTable[status]) : ('Error #' + status)));
+ obj.state = 1;
+ if (obj.onStep) obj.onStep(obj);
+ }
+
+ // ###BEGIN###{Certificates}
+ obj.xxSignWithDummyCaReturn = function (cert) {
+ obj.setVar('signed_cert', btoa(_arrayBufferToString(cert)));
+ obj.state = 1;
+ if (obj.onStep) obj.onStep(obj);
+ }
+ // ###END###{Certificates}
+
+ obj.toString = function (x) { if (typeof x == 'object') return JSON.stringify(x); return x; }
+
+ obj.reset();
+ return obj;
+}
+
+// Argument types: 0 = Variable, 1 = String, 2 = Integer, 3 = Label
+function script_compile(script, onmsg) {
+ var r = '', scriptlines = script.split('\n'), labels = {}, labelswap = [], swaps = [];
+ // Go thru each script line and encode it
+ for (var i in scriptlines) {
+ var scriptline = scriptlines[i];
+ if (scriptline.startsWith('##SWAP ')) { var x = scriptline.split(' '); if (x.length == 3) { swaps[x[1]] = x[2]; } } // Add a swap instance
+ if (scriptline[0] == '#' || scriptline.length == 0) continue; // Skip comments & blank lines
+ for (var x in swaps) { scriptline = scriptline.split(x).join(swaps[x]); } // Apply all swaps
+ var keywords = scriptline.match(/"[^"]*"|[^\s"]+/g);
+ if (keywords.length == 0) continue; // Skip blank lines
+ if (scriptline[0] == ':') { labels[keywords[0].toUpperCase()] = r.length; continue; } // Mark a label position
+ var funcIndex = script_functionTable1.indexOf(keywords[0].toLowerCase());
+ if (funcIndex == -1) { funcIndex = script_functionTable2.indexOf(keywords[0].toLowerCase()); if (funcIndex >= 0) funcIndex += 10000; }
+ if (funcIndex == -1) { funcIndex = script_functionTable3.indexOf(keywords[0].toLowerCase()); if (funcIndex >= 0) funcIndex += 20000; } // Optional methods
+ if (funcIndex == -1) { if (onmsg) { onmsg("Unabled to compile, unknown command: " + keywords[0]); } return ''; }
+ // Encode CommandId, CmdSize, ArgCount, Arg1Len, Arg1, Arg2Len, Arg2...
+ var cmd = ShortToStr(keywords.length - 1);
+ for (var j in keywords) {
+ if (j == 0) continue;
+ if (keywords[j][0] == ':') {
+ labelswap.push([keywords[j], r.length + cmd.length + 7]); // Add a label swap
+ cmd += ShortToStr(5) + String.fromCharCode(3) + IntToStr(0xFFFFFFFF); // Put an empty label
+ } else {
+ var argint = parseInt(keywords[j]);
+ if (argint == keywords[j]) {
+ cmd += ShortToStr(5) + String.fromCharCode(2) + IntToStr(argint);
+ } else {
+ if (keywords[j][0] == '"' && keywords[j][keywords[j].length - 1] == '"') {
+ cmd += ShortToStr(keywords[j].length - 1) + String.fromCharCode(1) + keywords[j].substring(1, keywords[j].length - 1);
+ } else {
+ cmd += ShortToStr(keywords[j].length + 1) + String.fromCharCode(0) + keywords[j];
+ }
+ }
+ }
+ }
+ cmd = ShortToStr(funcIndex) + ShortToStr(cmd.length + 4) + cmd;
+ r += cmd;
+ }
+ // Perform all the needed label swaps
+ for (i in labelswap) {
+ var label = labelswap[i][0].toUpperCase(), position = labelswap[i][1], target = labels[label];
+ if (target == undefined) { if (onmsg) { onmsg("Unabled to compile, unknown label: " + label); } return ''; }
+ r = r.substr(0, position) + IntToStr(target) + r.substr(position + 4);
+ }
+ return IntToStr(0x247D2945) + ShortToStr(1) + r;
+}
+
+// Decompile the script, intended for debugging only
+function script_decompile(binary, onecmd) {
+ var r = '', ptr = 6, labelcount = 0, labels = {};
+ if (onecmd >= 0) {
+ ptr = onecmd; // If we are decompiling just one command, set the ptr to that command.
+ } else {
+ if (binary.length < 6) { return '# Invalid script length'; }
+ var magic = ReadInt(binary, 0);
+ var version = ReadShort(binary, 4);
+ if (magic != 0x247D2945) { return '# Invalid binary script: ' + magic; }
+ if (version != 1) { return '# Invalid script version'; }
+ }
+ // Loop on each command, moving forward by the command length each time.
+ while (ptr < binary.length) {
+ var cmdid = ReadShort(binary, ptr);
+ var cmdlen = ReadShort(binary, ptr + 2);
+ var argcount = ReadShort(binary, ptr + 4);
+ var argptr = ptr + 6;
+ var argstr = '';
+ if (!(onecmd >= 0)) r += ":label" + (ptr - 6) + "\n";
+ // Loop on each argument, moving forward by the argument length each time
+ for (var i = 0; i < argcount; i++) {
+ var arglen = ReadShort(binary, argptr);
+ var argval = binary.substring(argptr + 2, argptr + 2 + arglen);
+ var argtyp = argval.charCodeAt(0);
+ if (argtyp == 0) { argstr += ' ' + argval.substring(1); } // Variable
+ else if (argtyp == 1) { argstr += ' \"' + argval.substring(1) + '\"'; } // String
+ else if (argtyp == 2) { argstr += ' ' + ReadInt(argval, 1); } // Integer
+ else if (argtyp == 3) { // Label
+ var target = ReadInt(argval, 1);
+ var label = labels[target];
+ if (!label) { label = ":label" + target; labels[label] = target; }
+ argstr += ' ' + label;
+ }
+ argptr += (2 + arglen);
+ }
+ // Go in the script function table to decode the function
+ if (cmdid < 10000) {
+ r += script_functionTable1[cmdid] + argstr + "\n";
+ } else {
+ if (cmdid >= 20000) {
+ r += script_functionTable3[cmdid - 20000] + argstr + "\n"; // Optional methods
+ } else {
+ r += script_functionTable2[cmdid - 10000] + argstr + "\n";
+ }
+ }
+ ptr += cmdlen;
+ if (onecmd >= 0) return r; // If we are decompiling just one command, exit now
+ }
+ // Remove all unused labels
+ var scriptlines = r.split('\n');
+ r = '';
+ for (var i in scriptlines) {
+ var line = scriptlines[i];
+ if (line[0] != ':') { r += line + '\n'; } else { if (labels[line]) { r += line + '\n'; } }
+ }
+ return r;
+}
diff --git a/amt-setupbin-0.1.0.js b/amt-setupbin-0.1.0.js
new file mode 100644
index 0000000..1797bae
--- /dev/null
+++ b/amt-setupbin-0.1.0.js
@@ -0,0 +1,273 @@
+/**
+* @description Intel(R) AMT Setup.bin Parser
+* @author Ylian Saint-Hilaire
+* @version v0.1.0
+*/
+
+// Intel(R) AMT Setup.bin GUID's
+var AmtSetupBinSetupGuids = [
+ "\xb5\x16\xfb\x71\x87\xcb\xf9\x4a\xb4\x41\xca\x7b\x38\x35\x78\xf9", // Version 1
+ "\x96\xb2\x81\x58\xcf\x6b\x72\x4c\x8b\x91\xa1\x5e\x51\x2e\x99\xc4", // Version 2
+ "\xa7\xf7\xf6\xc6\x89\xc4\xf6\x47\x93\xed\xe2\xe5\x02\x0d\xa5\x1d", // Version 3
+ "\xaa\xa9\x34\x52\xe1\x29\xa9\x44\x8d\x4d\x08\x1c\x07\xb9\x63\x53" // Version 4
+];
+
+// Notes about version 2 of setup.bin:
+// - Default "admin" must be followed by a new MEBx password
+// - ME_VARIABLE_IDENTIFIER_MANAGEABILITY_FEATURE_SELECTION may not appear after any CM settings
+// - CM_VARIABLE_IDENTIFIER_USER_DEFINED_CERT_ADD must be preceded by setting CM_VARIABLE_IDENTIFIER_USER_DEFINED_CERTS_CONFIG to (TODO!)
+
+// General notes:
+// - Setup.bin should always start with "CurrentMEBx Pwd", "newMebx Pwd", "manageability selection" (if present).
+
+// Intel(R) AMT variable identifiers
+// Type: 0 = Binar Stringy, 1 = Char, 2 = Short, 3 = Int
+var AmtSetupBinVarIds =
+{
+ 1: {
+ 1: [0, "Current MEBx Password"],
+ 2: [0, "New MEBx Password"],
+ 3: [1, "Manageability Feature Selection",
+ { 0: "None", 1: "Intel AMT" }],
+ 4: [1, "Firmware Local Update", // 0 = Disabled, 1 = Enabled, 2 = Password Protected
+ { 0: "Disabled", 1: "Enabled", 2: "Password Protected" }],
+ 5: [1, "Firmware Update Qualifier", // 0 = Always, 1 = Never, 2 = Restricted
+ { 0: "Always", 1: "Never", 2: "Restricted" }],
+ 6: [4, "Power Package"] // GUID Length (16 bytes), Intel AMT version 2.1, 3 and 4
+ },
+ 2: {
+ 1: [0, "Provisioning Preshared Key ID (PID)"],
+ 2: [0, "Provisioning Preshared Key (PPS)"],
+ 3: [0, "PKI DNS Suffix"], // 255 bytes max length
+ 4: [0, "Configuration Server FQDN"], // 255 bytes max length
+ 5: [1, "Remote Configuration Enabled (RCFG)", // 0 = Off, 1 = On
+ { 0: "Off", 1: "On" }],
+ 6: [1, "Pre-Installed Certificates Enabled", // 0 = Off, 1 = On
+ { 0: "Off", 1: "On" }],
+ 7: [1, "User Defined Certificate Configuration", // 0 = Disabled, 1 = Enabled, 2 = Delete
+ { 0: "Disabled", 1: "Enabled", 2: "Delete" }],
+ 8: [0, "User Defined Certificate Addition"], // 1 byte hash algo, 20 to 48 bytes hash, 1 byte name length, up to 32 bytes friendly name, 1 = SHA1 (20 bytes), 2 = SHA256 (32 bytes), 3 = SHA384 (48 bytes). Algo 2 & 3 are for version 3 and up.
+ 10: [1, "SOL/IDER Redirection Configuration", {
+ 0: "None", 1: "SOL only - User/Pass Disabled", 2: "IDER only - User/Pass Disabled", 3: "SOL+IDER - User/Pass Disabled",
+ 4: "None - User/Pass Enabled", 5: "SOL only - User/Pass Enabled", 6: "IDER only - User/Pass Enabled", 7: "SOL+IDER - User/Pass Enabled"
+ }],
+ 11: [0, "Hostname"], // 63 bytes max length
+ 12: [0, "Domain Name"], // 255 bytes max length
+ 13: [1, "DHCP", { 1: "Disabled", 2: "Enabled" }],
+ 14: [1, "Secure Firmware Update (SFWU)", // 0 = Disabled, 1 = Enabled
+ { 0: "Disabled", 1: "Enabled" }],
+ 15: [0, "ITO"],
+ 16: [1, "Provisioning Mode (PM)", // 1 = Enterprise, 2 = Small Buisness (SMB)
+ { 0: "Enterprise", 1: "Small Buisness"}],
+ 17: [0, "Provisioning Server Address"],
+ 18: [2, "Provision Server Port Number (PSPO)"],
+ 19: [0, "Static IPv4 Parameters"],
+ 20: [0, "VLAN"],
+ 21: [0, "PASS Policy Flag"],
+ 22: [0, "IPv6"], // Length is 204 bytes old format, 84 bytes new format, Version 3+ only
+ 23: [1, "Shared/Dedicated FQDN", // 0 = Dedicated, 1 = Shared. This option is valid only if configuring the hostname as well
+ { 0: "Dedicated", 1: "Shared" }],
+ 24: [1, "Dynamic DNS Update", // 0 = Disabled, 1 = Enabled
+ { 0: "Disabled", 1: "Enabled" }],
+ 25: [1, "Remote Desktop (KVM) State", // 0 = Disabled, 1 = Enabled
+ { 0: "Disabled", 1: "Enabled" }],
+ 26: [1, "Opt-in User Consent Option", // 0 = Disabled, 1 = KVM, 0xFF = ALL
+ { 0 : "Disabled", 1 : "KVM", 255 : "All" }],
+ 27: [1, "Opt-in Remote IT Consent Policy", // 0 = Disabled, 1 = Enabled. Allows user consent to be configured remotely.
+ { 0 : "Disabled", 1 : "Enabled"} ],
+ 28: [1, "ME Provision Halt Active", // 0 = Stop, 1 = Start. The "ME provisioning Halt/Activate" command must appear in the file only after "PKIDNSSuffix", "ConfigServerFQDN" and "Provisioning Server Address"
+ { 0 : "Stop", 1 : "Start"}],
+ 29: [1, "Manual Setup and Configuration", // 0 = Automated, 1 = Manual
+ { 0 : "Automated", 1 : "Manual"}],
+ 30: [3, "Support Channel Identifier"], // 4 bytes length. Support channel identifier (valid values: 1-65535)
+ 31: [0, "Support Channel Description"], // 60 bytes max. Friendly name used to describe the party representedby the support channel identifier.
+ 32: [0, "Service Account Number"], // 32 bytes max. Unique string identifier given to the end user by the service provider.
+ 33: [0, "Enrollement Passcode"], // 32 bytes max
+ 34: [3, "Service Type"], // 4 bytes length. 1 = Reactive, 2 = Proactive, 4 = One Time Session
+ 35: [0, "Service Provider Identifier"] // GUID Length (16 bytes)
+ }
+}
+
+
+// Parse the Setup.bin file
+var AmtSetupBinCreate = function (version, flags) {
+ var obj = {};
+ obj.fileType = version;
+ obj.recordChunkCount = 0;
+ obj.recordHeaderByteCount = 0;
+ obj.recordNumber = 0;
+ obj.majorVersion = version;
+ obj.minorVersion = 0;
+ obj.flags = flags;
+ obj.dataRecordsConsumed = 0;
+ obj.dataRecordChunkCount = 0;
+ obj.records = [];
+ return obj;
+}
+
+
+// Parse the Setup.bin file
+var AmtSetupBinDecode = function (file) {
+
+ // Format of the setup file header:
+ // FileTypeUUID(16) - uniquely identifies the file type. This identifier will remain valid and constant across all versions of the file type.
+ // RecordChunkCount(2) - indicates the number of 512-byte chunks occupied by this record, including all header, body, and reserved fields.
+ // RecordHeaderBytes(2) - indicates the length of the record header in bytes.
+ // RecordNumber(4) - uniquely identifies the record among all records in the file. The field contains a non-negative ordinal value. The value of this field is always zero in the Local Provisioning File Header Record.
+ // MajorVersion(1) - identifies the major version of the file format specification. This is a positive integer that is greater than or equal to 1. The Major Version number is incremented to indicate that changes have been introduced that will cause code written against a lower Major Version number to fail.
+ // MinorVersion(1) - identifies the minor version of the file format specification. This is an integer that is greater than or equal to 0. The Minor Version number is incremented to indicate that changes have been introduced that will not cause code written against the same Major Version and a lower Minor Version number to fail. The purpose of this behavior is to allow a single local provisioning file to be used for multiple generations of Intel® AMT platform.
+ // DataRecordCount(4) - indicates the total number of data records written in the file when it was created.
+ // DataRecordsConsumed(4) - is a counter value that begins at 0 and is incremented by 1 by each platform BIOS when it consumes a data record from the file. This value is used to determine the offset of the next data record in the file.
+ // DataRecordChunkCount(2) - contains the number of 512-byte chunks in each data record. All data records are the same length.
+ // ModuleList - contains a list of module identifiers. A module’s identifier appears in the list if and only if the data records contain entries for that module. Each module identifier is two bytes in length. The list is terminated by an identifier value of 0.
+
+ var obj = {}, UUID = file.substring(0, 16);
+ obj.fileType = 0;
+ for (var i in AmtSetupBinSetupGuids) { if (UUID == AmtSetupBinSetupGuids[i]) obj.fileType = (+i + 1); }
+ if (obj.fileType == 0) return; // Bad header
+ obj.recordChunkCount = ReadShortX(file, 16);
+ obj.recordHeaderByteCount = ReadShortX(file, 18);
+ obj.recordNumber = ReadIntX(file, 20);
+ obj.majorVersion = file.charCodeAt(24);
+ obj.minorVersion = file.charCodeAt(25);
+ obj.flags = ReadShortX(file, 26); // Flags: 1 = Do not consume records
+ var dataRecordCount = ReadIntX(file, 28);
+ obj.dataRecordsConsumed = ReadIntX(file, 32);
+ obj.dataRecordChunkCount = ReadShortX(file, 36);
+ obj.records = [];
+
+ var ptr = 512;
+ while (ptr + 512 <= file.length) {
+
+ // Format of a data record header:
+ // RecordTypeIdentifier(4) - identifies the type of record (in this case a data record). Record Identifiers: Invalid - 0, Data Record - 1
+ // RecordFlags(4) - contains a set of bit flags that characterize the record.
+ // RecordChunkCount(2) - contains the number of 512-byte chunks occupied by the record including all header, body, and reserved fields.
+ // RecordHeaderByteCount(2) - indicates the length of the record header in bytes.
+ // RecordNumber(4) - uniquely identifies the record among all records in the file, including invalid as well as valid records. The identifier is a non-negative integer.
+
+ var r = {};
+ r.typeIdentifier = ReadIntX(file, ptr);
+ r.flags = ReadIntX(file, ptr + 4); // Flags: 1 = Valid, 2 = Scrambled
+ r.chunkCount = ReadShortX(file, ptr + 8);
+ r.headerByteCount = ReadShortX(file, ptr + 10);
+ r.number = ReadIntX(file, ptr + 12);
+ r.variables = [];
+
+ var ptr2 = 0, recbin = file.substring(ptr + 24, ptr + 512);
+ if ((r.flags & 2) != 0) { recbin = AmtSetupBinDescrambleRecordData(recbin); } // De-Scramble the record
+ while (1) {
+
+ // Format of a data record entry:
+ // ModuleIdentifier(2) - identifies the target ME module for the entry.
+ // VariableIdentifier(2) - an enumeration value that identifies the variable. Variable identifiers are unique to each ModuleIdentifier.
+ // VariableLength(2) - is the length of the variable value in bytes.
+ // VariableValue - is the value to be assigned to the variable.
+
+ var v = {};
+ v.moduleid = ReadShortX(recbin, ptr2);
+ v.varid = ReadShortX(recbin, ptr2 + 2);
+ if (v.moduleid == 0 || v.varid == 0) break;
+ if (AmtSetupBinVarIds[v.moduleid][v.varid]) {
+ v.length = ReadShortX(recbin, ptr2 + 4);
+ v.type = AmtSetupBinVarIds[v.moduleid][v.varid][0];
+ v.desc = AmtSetupBinVarIds[v.moduleid][v.varid][1];
+ v.value = recbin.substring(ptr2 + 8, ptr2 + 8 + v.length);
+ if (v.type == 1 && v.length == 1) v.value = v.value.charCodeAt(0); // 1 byte number
+ else if (v.type == 2 && v.length == 2) v.value = ReadShortX(v.value, 0); // 2 byte number
+ else if (v.type == 3 && v.length == 4) v.value = ReadIntX(v.value, 0); // 4 byte number
+ else if (v.type == 4) v.value = guidToStr(rstr2hex(v.value)); // GUID
+ r.variables.push(v);
+ }
+ ptr2 += (8 + (Math.floor((v.length + 3) / 4) * 4));
+ }
+
+ // Sort the variables
+ r.variables.sort(AmtSetupBinVariableCompare);
+
+ obj.records.push(r);
+ ptr += 512;
+ }
+
+ if (dataRecordCount != obj.records.length) return; // Mismatch record count
+ return obj;
+}
+
+// Construct a Setup.bin file
+var AmtSetupBinEncode = function (obj) {
+ if (obj.fileType < 1 && obj.fileType > AmtSetupBinSetupGuids.length) return null;
+ var out = [], r = AmtSetupBinSetupGuids[obj.fileType - 1], reccount = 0;
+ r += ShortToStrX(obj.recordChunkCount);
+ r += ShortToStrX(obj.recordHeaderByteCount);
+ r += IntToStrX(obj.recordNumber);
+ r += String.fromCharCode(obj.majorVersion, obj.minorVersion);
+ r += ShortToStrX(obj.flags); // Flags: 1 = Do not consume records
+ r += IntToStrX(obj.records.length);
+ r += IntToStrX(obj.dataRecordsConsumed);
+ r += ShortToStrX(obj.dataRecordChunkCount);
+ while (r.length < 512) { r += "\0"; } // Pad the header
+ out.push(r);
+
+ // Write each record
+ for (var i in obj.records) {
+ var r2 = "", rec = obj.records[i];
+ r2 += IntToStrX(rec.typeIdentifier);
+ r2 += IntToStrX(rec.flags);
+ r2 += IntToStrX(0); // Reserved
+ r2 += IntToStrX(0); // Reserved
+ r2 += ShortToStrX(1); // rec.chunkCount
+ r2 += ShortToStrX(24); // rec.headerByteCount
+ r2 += IntToStrX(++reccount);
+
+ // Sort the variables
+ rec.variables.sort(AmtSetupBinVariableCompare);
+
+ /*
+ // Change variable priority
+ AmtSetupBinMoveToTop(r.variables, 1, 3); // Manageability Feature Selection
+ AmtSetupBinMoveToTop(r.variables, 1, 2); // New MEBx password
+ AmtSetupBinMoveToTop(r.variables, 1, 1); // Current MEBx password
+ */
+
+ // Write each variable
+ for (var j in rec.variables) {
+ var r3 = "", v = rec.variables[j], data = v.value;
+ v.type = AmtSetupBinVarIds[v.moduleid][v.varid][0]; // Set the correct type if not alreay connect
+ if ((v.type > 0) && (v.type < 4)) { // If this is a numeric value, encode it correctly
+ data = parseInt(data);
+ if (v.type == 1) data = String.fromCharCode(data);
+ if (v.type == 2) data = ShortToStrX(data);
+ if (v.type == 3) data = IntToStrX(data);
+ }
+ if (v.type == 4) { data = hex2rstr(guidToStr(data.split('-').join('')).split('-').join('')); }
+ r3 += ShortToStrX(v.moduleid); // Module Identifier
+ r3 += ShortToStrX(v.varid); // Variable Identifier
+ r3 += ShortToStrX(data.length); // Variable Length
+ r3 += ShortToStrX(0); // Reserved
+ r3 += data; // Variable Data
+ while (r3.length % 4 != 0) { r3 += "\0"; } // Pad the variable
+ r2 += r3;
+ }
+
+ while (r2.length < 512) { r2 += "\0"; } // Pad the record
+ if ((rec.flags & 2) != 0) { r2 = r2.substring(0, 24) + AmtSetupBinScrambleRecordData(r2.substring(24)); } // Scramble the record starting at byte 24, after the header
+ out.push(r2);
+ }
+ return out.join('');
+}
+
+// Used to sort variables
+function AmtSetupBinVariableCompare(a, b) {
+ if (a.moduleid > b.moduleid) return 1;
+ if (a.moduleid < b.moduleid) return -1;
+ if (a.varid > b.varid) return 1;
+ if (a.varid < b.varid) return -1;
+ return 0;
+}
+
+// Scramble and un-scramble records
+function AmtSetupBinScrambleRecordData(data) { var out = ""; for (var i = 0; i < data.length; i++) { out += String.fromCharCode((data.charCodeAt(i) + 17) & 0xFF); } return out; }
+function AmtSetupBinDescrambleRecordData(data) { var out = ""; for (var i = 0; i < data.length; i++) { out += String.fromCharCode((data.charCodeAt(i) + 0xEF) & 0xFF); } return out; }
+
+// Find a moduleid/varid in the variable list, if found, move it to the top
+//function AmtSetupBinMoveToTop(variables, moduleid, varid) { var i = -1; for (var j in variables) { if ((variables[j].moduleid == moduleid) && (variables[j].varid == varid)) { i = j; } } if (i > 1) { ArrayElementMove(variables, i, 0); } }
diff --git a/amt-terminal-0.0.2.js b/amt-terminal-0.0.2.js
new file mode 100644
index 0000000..fb2ee4a
--- /dev/null
+++ b/amt-terminal-0.0.2.js
@@ -0,0 +1,813 @@
+/**
+* @description Remote Terminal
+* @author Ylian Saint-Hilaire
+* @version v0.0.2c
+*/
+
+// https://invisible-island.net/xterm/ctlseqs/ctlseqs.html
+// https://www.x.org/docs/xterm/ctlseqs.pdf
+
+// Construct a MeshServer object
+var CreateAmtRemoteTerminal = function (divid, options) {
+ var obj = {};
+ obj.DivId = divid;
+ obj.DivElement = document.getElementById(divid);
+ obj.protocol = 1; // SOL
+ if (options && options.protocol) { obj.protocol = options.protocol; } // 1 = Normal, 6 = PowerShell
+ // ###BEGIN###{Terminal-Enumation-All}
+ obj.terminalEmulation = 1;
+ // ###END###{Terminal-Enumation-All}
+ obj.fxEmulation = 0;
+ obj.lineFeed = '\r\n';
+ obj.debugmode = 0;
+
+ obj.width = 80; // 80 or 100
+ obj.height = 25; // 25 or 30
+ obj.heightLock = 0;
+
+ var _Terminal_CellHeight = 21;
+ var _Terminal_CellWidth = 13;
+ var _TermColors = ['000000', 'BB0000', '00BB00', 'BBBB00', '0000BB', 'BB00BB', '00BBBB', 'BBBBBB', '555555', 'FF5555', '55FF55', 'FFFF55', '5555FF', 'FF55FF', '55FFFF', 'FFFFFF'];
+ var _TermCurrentReverse = 0;
+ var _TermCurrentFColor = 7;
+ var _TermCurrentBColor = 0;
+ var _TermLineWrap = true;
+ var _termx = 0;
+ var _termy = 0;
+ var _termsavex = 0;
+ var _termsavey = 0;
+ var _termstate = 0;
+ var _escNumber = [];
+ var _escNumberPtr = 0;
+ var _escNumberMode = 0;
+ var _scratt = [];
+ var _tscreen = [];
+ var _VTUNDERLINE = 1;
+ var _VTREVERSE = 2;
+ var _backSpaceErase = false;
+ var _cursorVisible = true;
+ var _scrollRegion;
+ var _altKeypadMode = false;
+ var scrollBackBuffer = [];
+ // ###BEGIN###{Terminal-Enumation-UTF8}
+ var utf8decodeBuffer = '';
+ // ###END###{Terminal-Enumation-UTF8}
+ // ###BEGIN###{Terminal-Enumation-All}
+ var utf8decodeBuffer = '';
+ // ###END###{Terminal-Enumation-All}
+ obj.title = null;
+ obj.onTitleChange = null;
+
+ obj.Start = function () { }
+
+ obj.Init = function (width, height) {
+ obj.width = width ? width : 80;
+ obj.height = height ? height : 25;
+ for (var y = 0; y < obj.height; y++) {
+ _tscreen[y] = [];
+ _scratt[y] = [];
+ for (var x = 0; x < obj.width; x++) { _tscreen[y][x] = ' '; _scratt[y][x] = (7 << 6); }
+ }
+ obj.TermInit();
+ obj.TermDraw();
+ }
+
+ obj.xxStateChange = function (newstate) {
+ if ((newstate == 3) && (options != null) && (options.xterm == true)) { obj.TermSendKeys('stty rows ' + obj.height + ' cols ' + obj.width + '\nclear\n'); }
+ }
+
+ obj.ProcessData = function (str) {
+ if (obj.debugmode == 2) { console.log("TRecv(" + str.length + "): " + rstr2hex(str)); }
+ if (obj.capture != null) obj.capture += str;
+ // ###BEGIN###{Terminal-Enumation-UTF8}
+ try { str = decode_utf8(utf8decodeBuffer + str); } catch (ex) { utf8decodeBuffer += str; return; } // If we get data in the middle of a UTF-8 code, buffer it for next time.
+ utf8decodeBuffer = '';
+ // ###END###{Terminal-Enumation-UTF8}
+ // ###BEGIN###{Terminal-Enumation-All}
+ if (obj.terminalEmulation == 0) { try { str = decode_utf8(utf8decodeBuffer + str); } catch (ex) { utf8decodeBuffer += str; return; } } // If we get data in the middle of a UTF-8 code, buffer it for next time.
+ utf8decodeBuffer = '';
+ // ###END###{Terminal-Enumation-All}
+ _ProcessVt100EscString(str); obj.TermDraw();
+ }
+
+ function _ProcessVt100EscString(str) { for (var i = 0; i < str.length; i++) _ProcessVt100EscChar(String.fromCharCode(str.charCodeAt(i)), str.charCodeAt(i)); }
+
+ function _ProcessVt100EscChar(b, c) {
+ switch (_termstate) {
+ case 0: // Normal Term State
+ switch (c) {
+ case 27: // ESC
+ _termstate = 1;
+ _escNumber = [];
+ _escNumberPtr = 0;
+ _escNumberMode = 0;
+ break;
+ default:
+ // Process a single char
+ _ProcessVt100Char(b);
+ break;
+ }
+ break;
+ case 1:
+ switch (b) {
+ case '[':
+ _termstate = 2;
+ break;
+ case '(':
+ _termstate = 4;
+ break;
+ case ')':
+ _termstate = 5;
+ break;
+ case ']':
+ _termstate = 6; // xterm strings
+ break;
+ case '=':
+ // Set alternate keypad mode
+ _altKeypadMode = true;
+ _termstate = 0;
+ break;
+ case '>':
+ // Set numeric keypad mode
+ _altKeypadMode = false;
+ _termstate = 0;
+ break;
+ case '7':
+ // Save Cursor
+ _termsavex = _termx;
+ _termsavey = _termy;
+ _termstate = 0;
+ break;
+ case '8':
+ // Restore Cursor
+ _termx = _termsavex;
+ _termy = _termsavey;
+ _termstate = 0;
+ break;
+ case 'M':
+ // Scroll down one
+ var x = 1;
+ for (var y = _scrollRegion[1]; y >= _scrollRegion[0] + x; y--) {
+ for (var z = 0; z < obj.width; z++) { _tscreen[y][z] = _tscreen[y - x][z]; _scratt[y][z] = _scratt[y - x][z]; }
+ }
+ for (var y = _scrollRegion[0] + x - 1; y > _scrollRegion[0] - 1; y--) {
+ for (var z = 0; z < obj.width; z++) { _tscreen[y][z] = ' '; _scratt[y][z] = (7 << 6); }
+ }
+ _termstate = 0;
+ break;
+ default:
+ console.log('unknown terminal short code', b);
+ _termstate = 0;
+ break;
+ }
+ break;
+ case 2:
+ if (b >= '0' && b <= '9') {
+ // This is a number
+ if (!_escNumber[_escNumberPtr]) { _escNumber[_escNumberPtr] = (b - '0'); }
+ else { _escNumber[_escNumberPtr] = ((_escNumber[_escNumberPtr] * 10) + (b - '0')); }
+ break;
+ } else if (b == ';') {
+ // New number
+ _escNumberPtr++;
+ break;
+ } else if (b == '?') {
+ _escNumberMode = 1;
+ break;
+ } else {
+ // Process Escape Sequence
+ if (!_escNumber[0]) _escNumber[0] = 0;
+ _ProcessEscapeHandler(b, _escNumber, _escNumberPtr + 1, _escNumberMode);
+ _termstate = 0;
+ }
+ break;
+ case 4: // '(' Code
+ _termstate = 0;
+ break;
+ case 5: // ')' Code
+ _termstate = 0;
+ break;
+ case 6: // ']' Code, xterm
+ var bx = b.charCodeAt(0);
+ if (b == ';') {
+ _escNumberPtr++;
+ } else if (bx == 7) {
+ _ProcessXTermHandler(_escNumber);
+ _termstate = 0;
+ } else {
+ if (!_escNumber[_escNumberPtr]) { _escNumber[_escNumberPtr] = b; }
+ else { _escNumber[_escNumberPtr] += b; }
+ }
+ break;
+ }
+ }
+
+ function _ProcessXTermHandler(_escNumber) {
+ if (_escNumber.length == 0) return;
+ var cmd = parseInt(_escNumber[0]);
+ if ((cmd == 0 || cmd == 2) && (_escNumber.length > 1) && (_escNumber[1] != '?')) {
+ if (obj.onTitleChange) { obj.onTitleChange(obj, obj.title = _escNumber[1]); }
+ }
+ }
+
+ function _ProcessEscapeHandler(code, args, argslen, mode) {
+ //console.log('process', code, args, mode);
+ if (mode == 1) {
+ switch (code) {
+ case 'l': // Hide the cursor
+ if (args[0] == 25) { _cursorVisible = false; }
+ break;
+ case 'h': // Show the cursor
+ if (args[0] == 25) { _cursorVisible = true; }
+ break;
+ }
+ } else if (mode == 0) {
+ var i;
+ switch (code) {
+ case 'c': // ResetDevice
+ // Reset
+ obj.TermResetScreen();
+ break;
+ case 'A': // Move cursor up n lines
+ if (argslen == 1) {
+ if (args[0] == 0) { _termy--; } else { _termy -= args[0]; }
+ if (_termy < 0) _termy = 0;
+ }
+ break;
+ case 'B': // Move cursor down n lines
+ if (argslen == 1) {
+ if (args[0] == 0) { _termy++; } else { _termy += args[0]; }
+ if (_termy > obj.height) _termy = obj.height;
+ }
+ break;
+ case 'C': // Move cursor right n lines
+ if (argslen == 1) {
+ if (args[0] == 0) { _termx++; } else { _termx += args[0]; }
+ if (_termx > obj.width) _termx = obj.width;
+ }
+ break;
+ case 'D': // Move cursor left n lines
+ if (argslen == 1) {
+ if (args[0] == 0) { _termx--; } else { _termx -= args[0]; }
+ if (_termx < 0) _termx = 0;
+ }
+ break;
+ case 'd': // Set cursor to line n
+ if (argslen == 1) {
+ _termy = args[0] - 1;
+ if (_termy > obj.height) _termy = obj.height;
+ if (_termy < 0) _termy = 0;
+ }
+ break;
+ case 'G': // Set cursor to col n
+ if (argslen == 1) {
+ _termx = args[0] - 1;
+ if (_termx < 0) _termx = 0;
+ if (_termx > (obj.width - 1)) _termx = (obj.width - 1);
+ }
+ break;
+ case 'P': // Delete X Character(s), default 1 char
+ var x = 1;
+ if (argslen == 1) { x = args[0]; }
+ for (i = _termx; i < obj.width - x; i++) { _tscreen[_termy][i] = _tscreen[_termy][i + x]; _scratt[_termy][i] = _scratt[_termy][i + x]; }
+ for (i = (obj.width - x); i < obj.width; i++) { _tscreen[_termy][i] = ' '; _scratt[_termy][i] = (7 << 6); }
+ break;
+ case 'L': // Insert X Line(s), default 1 char
+ var linecount = 1;
+ if (argslen == 1) { linecount = args[0]; }
+ if (linecount == 0) { linecount = 1; }
+ for (y = _scrollRegion[1]; y >= _termy + linecount; y--) {
+ _tscreen[y] = _tscreen[y - linecount];
+ _scratt[y] = _scratt[y - linecount];
+ }
+ for (y = _termy; y < _termy + linecount; y++) {
+ _tscreen[y] = [];
+ _scratt[y] = [];
+ for (x = 0; x < obj.width; x++) { _tscreen[y][x] = ' '; _scratt[y][x] = (7 << 6); }
+ }
+ break;
+ case 'J': // ClearScreen:
+ if (argslen == 1 && args[0] == 2) {
+ obj.TermClear((_TermCurrentBColor << 12) + (_TermCurrentFColor << 6)); // Erase entire screen
+ _termx = 0;
+ _termy = 0;
+ scrollBackBuffer = [];
+ }
+ else if (argslen == 0 || argslen == 1 && args[0] == 0) // Erase cursor down
+ {
+ _EraseCursorToEol();
+ for (i = _termy + 1; i < obj.height; i++) _EraseLine(i);
+ }
+ else if (argslen == 1 && args[0] == 1) // Erase cursor up
+ {
+ _EraseCursorToEol();
+ for (i = 0; i < _termy - 1; i++) _EraseLine(i);
+ }
+ break;
+ case 'H': // MoveCursor:
+ if (argslen == 2) {
+ if (args[0] < 1) args[0] = 1;
+ if (args[1] < 1) args[1] = 1;
+ if (args[0] > obj.height) args[0] = obj.height;
+ if (args[1] > obj.width) args[1] = obj.width;
+ _termy = args[0] - 1;
+ _termx = args[1] - 1;
+ } else {
+ _termy = 0;
+ _termx = 0;
+ }
+ break;
+ case 'm': // ScreenAttribs:
+ // Change attributes
+ for (i = 0; i < argslen; i++) {
+ if (!args[i] || args[i] == 0) {
+ // Reset Attributes
+ _TermCurrentBColor = 0;
+ _TermCurrentFColor = 7;
+ _TermCurrentReverse = 0;
+ }
+ else if (args[i] == 1) {
+ // Bright
+ if (_TermCurrentFColor < 8) _TermCurrentFColor += 8;
+ }
+ else if (args[i] == 2 || args[i] == 22) {
+ // Dim
+ if (_TermCurrentFColor >= 8) _TermCurrentFColor -= 8;
+ }
+ else if (args[i] == 7) {
+ // Set Reverse attribute true
+ _TermCurrentReverse = 2;
+ }
+ else if (args[i] == 27) {
+ // Set Reverse attribute false
+ _TermCurrentReverse = 0;
+ }
+ else if (args[i] >= 30 && args[i] <= 37) {
+ // Set Foreground Color
+ var bright = (_TermCurrentFColor >= 8);
+ _TermCurrentFColor = (args[i] - 30);
+ if (bright && _TermCurrentFColor <= 8) _TermCurrentFColor += 8;
+ }
+ else if (args[i] >= 40 && args[i] <= 47) {
+ // Set Background Color
+ _TermCurrentBColor = (args[i] - 40);
+ }
+ else if (args[i] >= 90 && args[i] <= 99) {
+ // Set Bright Foreground Color
+ _TermCurrentFColor = (args[i] - 82);
+ }
+ else if (args[i] >= 100 && args[i] <= 109) {
+ // Set Bright Background Color
+ _TermCurrentBColor = (args[i] - 92);
+ }
+ }
+ break;
+ case 'K': // EraseLine:
+ if (argslen == 0 || (argslen == 1 && (!args[0] || args[0] == 0))) {
+ _EraseCursorToEol(); // Erase from the cursor to the end of the line
+ } else if (argslen == 1) {
+ if (args[0] == 1) { // Erase from the beginning of the line to the cursor
+ _EraseBolToCursor();
+ } else if (args[0] == 2) { // Erase the line with the cursor
+ _EraseLine(_termy);
+ }
+ }
+ break;
+ case 'h': // EnableLineWrap:
+ _TermLineWrap = true;
+ break;
+ case 'l': // DisableLineWrap:
+ _TermLineWrap = false;
+ break;
+ case 'r': // Set the scroll region
+ if (argslen == 2) { _scrollRegion = [args[0] - 1, args[1] - 1]; }
+ if (_scrollRegion[0] < 0) { _scrollRegion[0] = 0; }
+ if (_scrollRegion[0] > (obj.height - 1)) { _scrollRegion[0] = (obj.height - 1); }
+ if (_scrollRegion[1] < 0) { _scrollRegion[1] = 0; }
+ if (_scrollRegion[1] > (obj.height - 1)) { _scrollRegion[1] = (obj.height - 1); }
+ if (_scrollRegion[0] > _scrollRegion[1]) { _scrollRegion[0] = _scrollRegion[1]; }
+ break;
+ case 'S': // Scroll up the scroll region X lines, default 1
+ var x = 1;
+ if (argslen == 1) { x = args[0] }
+ for (var y = _scrollRegion[0]; y <= _scrollRegion[1] - x; y++) {
+ for (var z = 0; z < obj.width; z++) { _tscreen[y][z] = _tscreen[y + x][z]; _scratt[y][z] = _scratt[y + x][z]; }
+ }
+ for (var y = _scrollRegion[1] - x + 1; y < _scrollRegion[1]; y++) {
+ for (var z = 0; z < obj.width; z++) { _tscreen[y][z] = ' '; _scratt[y][z] = (7 << 6); }
+ }
+ break;
+ case 'M': // Delete X lines, default 1
+ var x = 1;
+ if (argslen == 1) { x = args[0] }
+ for (var y = _termy; y <= _scrollRegion[1] - x; y++) {
+ for (var z = 0; z < obj.width; z++) { _tscreen[y][z] = _tscreen[y + x][z]; _scratt[y][z] = _scratt[y + x][z]; }
+ }
+ for (var y = _scrollRegion[1] - x + 1; y < _scrollRegion[1]; y++) {
+ for (var z = 0; z < obj.width; z++) { _tscreen[y][z] = ' '; _scratt[y][z] = (7 << 6); }
+ }
+ break;
+ case 'T': // Scroll down the scroll region X lines, default 1
+ var x = 1;
+ if (argslen == 1) { x = args[0] }
+ for (var y = _scrollRegion[1]; y > _scrollRegion[0] + x; y--) {
+ for (var z = 0; z < obj.width; z++) { _tscreen[y][z] = _tscreen[y - x][z]; _scratt[y][z] = _scratt[y - x][z]; }
+ }
+ for (var y = _scrollRegion[0] + x; y > _scrollRegion[0]; y--) {
+ for (var z = 0; z < obj.width; z++) { _tscreen[y][z] = ' '; _scratt[y][z] = (7 << 6); }
+ }
+ break;
+ case 'X': // Erase X characters, default 1
+ var x = 1, xx = _termx, yy = _termy;
+ if (argslen == 1) { x = args[0] }
+ while ((x > 0) && (yy < obj.height)) { _tscreen[yy][xx] = ' '; xx++; x--; if (xx >= obj.width) { xx = 0; yy++; } }
+ break;
+ default:
+ //if (code != '@') alert(code);
+ console.log('unknown terminal code', code, args, mode);
+ break;
+ }
+ }
+ }
+
+ obj.ProcessVt100String = function (str) {
+ for (var i = 0; i < str.length; i++) _ProcessVt100Char(String.fromCharCode(str.charCodeAt(i)));
+ }
+
+ // ###BEGIN###{Terminal-Enumation-All}
+ var AsciiToUnicode = [
+ 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7,
+ 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5,
+ 0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9,
+ 0x00ff, 0x00d6, 0x00dc, 0x00a2, 0x00a3, 0x00a5, 0x20a7, 0x0192,
+ 0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00da,
+ 0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb,
+ 0x2593, 0x2592, 0x2591, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
+ 0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510,
+ 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f,
+ 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567,
+ 0x2568, 0x2564, 0x2565, 0x2568, 0x2558, 0x2552, 0x2553, 0x256b,
+ 0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258b, 0x2590, 0x2580,
+ 0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4,
+ 0x03c6, 0x03b8, 0x2126, 0x03b4, 0x221e, 0x00f8, 0x03b5, 0x220f,
+ 0x2261, 0x00b1, 0x2265, 0x2266, 0x2320, 0x2321, 0x00f7, 0x2248,
+ 0x00b0, 0x2022, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x220e, 0x00a0
+ ];
+
+ var AsciiToUnicodeIntel = [
+ 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7,
+ 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5,
+ 0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9,
+ 0x00ff, 0x00d6, 0x00dc, 0x00a2, 0x00a3, 0x00a5, 0x20a7, 0x0192,
+ 0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00da,
+ 0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ae, 0x00bb,
+ 0x2593, 0x2592, 0x2591, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
+ 0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510,
+ 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f,
+ 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567,
+ 0x2568, 0x2564, 0x2565, 0x2568, 0x2558, 0x2552, 0x2553, 0x256b,
+ 0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258b, 0x2590, 0x2580,
+ 0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4,
+ 0x03c6, 0x03b8, 0x2126, 0x03b4, 0x221e, 0x00f8, 0x03b5, 0x220f,
+ 0x2261, 0x00b1, 0x2265, 0x2266, 0x2320, 0x2321, 0x00f7, 0x2248,
+ 0x00b0, 0x2022, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x220e, 0x00a0
+ ];
+ // ###END###{Terminal-Enumation-All}
+
+ // ###BEGIN###{Terminal-Enumation-ASCII}
+ var AsciiToUnicode = [
+ 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7,
+ 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5,
+ 0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9,
+ 0x00ff, 0x00d6, 0x00dc, 0x00a2, 0x00a3, 0x00a5, 0x20a7, 0x0192,
+ 0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00da,
+ 0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb,
+ 0x2593, 0x2592, 0x2591, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
+ 0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510,
+ 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f,
+ 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567,
+ 0x2568, 0x2564, 0x2565, 0x2568, 0x2558, 0x2552, 0x2553, 0x256b,
+ 0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258b, 0x2590, 0x2580,
+ 0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4,
+ 0x03c6, 0x03b8, 0x2126, 0x03b4, 0x221e, 0x00f8, 0x03b5, 0x220f,
+ 0x2261, 0x00b1, 0x2265, 0x2266, 0x2320, 0x2321, 0x00f7, 0x2248,
+ 0x00b0, 0x2022, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x220e, 0x00a0
+ ];
+ // ###END###{Terminal-Enumation-ASCII}
+
+ // ###BEGIN###{Terminal-Enumation-Intel}
+ var AsciiToUnicodeIntel = [
+ 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7,
+ 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5,
+ 0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9,
+ 0x00ff, 0x00d6, 0x00dc, 0x00a2, 0x00a3, 0x00a5, 0x20a7, 0x0192,
+ 0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00da,
+ 0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ae, 0x00bb,
+ 0x2593, 0x2592, 0x2591, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
+ 0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510,
+ 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f,
+ 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567,
+ 0x2568, 0x2564, 0x2565, 0x2568, 0x2558, 0x2552, 0x2553, 0x256b,
+ 0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258b, 0x2590, 0x2580,
+ 0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4,
+ 0x03c6, 0x03b8, 0x2126, 0x03b4, 0x221e, 0x00f8, 0x03b5, 0x220f,
+ 0x2261, 0x00b1, 0x2265, 0x2266, 0x2320, 0x2321, 0x00f7, 0x2248,
+ 0x00b0, 0x2022, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x220e, 0x00a0
+ ];
+ // ###END###{Terminal-Enumation-Intel}
+
+ function _ProcessVt100Char(c) {
+ if (c == '\0' || c.charCodeAt() == 7) return; // Ignore null & bell
+ var ch = c.charCodeAt();
+ //console.log('_ProcessVt100Char', ch, c);
+
+ // ###BEGIN###{Terminal-Enumation-All}
+ // UTF8 Terminal
+ if (obj.terminalEmulation == 1) {
+ // ANSI - Extended ASCII emulation.
+ if ((ch & 0x80) != 0) { c = String.fromCharCode(AsciiToUnicode[ch & 0x7F]); }
+ } else if (obj.terminalEmulation == 2) {
+ // ANSI - Intel Extended ASCII emulation.
+ if ((ch & 0x80) != 0) { c = String.fromCharCode(AsciiToUnicodeIntel[ch & 0x7F]); }
+ }
+ // ###END###{Terminal-Enumation-All}
+
+ // ###BEGIN###{Terminal-Enumation-ASCII}
+ // ANSI - Extended ASCII emulation.
+ //if ((ch & 0x80) != 0) { c = String.fromCharCode(AsciiToUnicode[ch & 0x7F]); }
+ // ###END###{Terminal-Enumation-ASCII}
+
+ // ###BEGIN###{Terminal-Enumation-Intel}
+ // ANSI - Intel Extended ASCII emulation.
+ //if ((ch & 0x80) != 0) { c = String.fromCharCode(AsciiToUnicodeIntel[ch & 0x7F]); }
+ // ###END###{Terminal-Enumation-Intel}
+
+ //if (ch < 32 && ch != 10 && ch != 13) alert(ch);
+ switch (ch) {
+ case 16: { c = ' '; break; } // This is an odd char that show up on Intel BIOS's.
+ case 24: { c = '↑'; break; }
+ case 25: { c = '↓'; break; }
+ }
+
+ if (_termx > obj.width) _termx = obj.width;
+ if (_termy > (obj.height - 1)) _termy = (obj.height - 1);
+
+ switch (c) {
+ case '\b': // Backspace
+ if (_termx > 0) {
+ _termx--;
+ if (_backSpaceErase) { _TermDrawChar(' '); }
+ }
+ break;
+ case '\t': // tab
+ var tab = 8 - (_termx % 8)
+ for (var x = 0; x < tab; x++) _ProcessVt100Char(" ");
+ break;
+ case '\n': // Linefeed
+ _termy++;
+ if (_termy > _scrollRegion[1]) {
+ // Move everything up one line
+ obj.recordLineTobackBuffer(0);
+ _TermMoveUp(1);
+ _termy = _scrollRegion[1];
+ }
+ if (obj.lineFeed = '\r') { _termx = 0; } // *** If we are in Linux mode, \n will also return the cursor to the first col
+ break;
+ case '\r': // Carriage Return
+ _termx = 0;
+ break;
+ default:
+ if (_termx >= obj.width) {
+ _termx = 0;
+ if (_TermLineWrap) { _termy++; }
+ if (_termy >= (obj.height - 1)) { _TermMoveUp(1); _termy = (obj.height - 1); }
+ }
+ _TermDrawChar(c);
+ _termx++;
+ break;
+ }
+ }
+
+ function _TermDrawChar(c) {
+ _tscreen[_termy][_termx] = c;
+ _scratt[_termy][_termx] = (_TermCurrentFColor << 6) + (_TermCurrentBColor << 12) + _TermCurrentReverse;
+ }
+
+ obj.TermClear = function(TermColor) {
+ for (var y = 0; y < obj.height; y++) {
+ for (var x = 0; x < obj.width; x++) {
+ _tscreen[y][x] = ' ';
+ _scratt[y][x] = TermColor;
+ }
+ }
+ scrollBackBuffer = [];
+ }
+
+ obj.TermResetScreen = function () {
+ _TermCurrentReverse = 0;
+ _TermCurrentFColor = 7;
+ _TermCurrentBColor = 0;
+ _TermLineWrap = _cursorVisible = true;
+ _termx = _termy = 0;
+ _backSpaceErase = false;
+ _scrollRegion = [0, (obj.height - 1)];
+ _altKeypadMode = false;
+ obj.TermClear(7 << 6);
+ // ###BEGIN###{Terminal-Enumation-UTF8}
+ //utf8decodeBuffer = '';
+ // ###END###{Terminal-Enumation-UTF8}
+ // ###BEGIN###{Terminal-Enumation-All}
+ utf8decodeBuffer = '';
+ // ###END###{Terminal-Enumation-All}
+ }
+
+ function _EraseCursorToEol() {
+ var t = (_TermCurrentFColor << 6) + (_TermCurrentBColor << 12) + _TermCurrentReverse;
+ for (var x = _termx; x < obj.width; x++) {
+ _tscreen[_termy][x] = ' ';
+ _scratt[_termy][x] = t;
+ }
+ }
+
+ function _EraseBolToCursor() {
+ var t = (_TermCurrentFColor << 6) + (_TermCurrentBColor << 12) + _TermCurrentReverse;
+ for (var x = 0; x < _termx; x++) {
+ _tscreen[_termy][x] = ' ';
+ _scratt[_termy][x] = t;
+ }
+ }
+
+ function _EraseLine(line) {
+ var t = (_TermCurrentFColor << 6) + (_TermCurrentBColor << 12) + _TermCurrentReverse;
+ for (var x = 0; x < obj.width; x++) {
+ _tscreen[line][x] = ' ';
+ _scratt[line][x] = t;
+ }
+ }
+
+ obj.TermSendKeys = function (keys) { if (obj.debugmode == 2) { console.log("TSend(" + keys.length + "): " + rstr2hex(keys), keys); } if (obj.parent) { obj.parent.Send(keys); } }
+ obj.TermSendKey = function (key) { if (obj.debugmode == 2) { console.log("TSend(1): " + rstr2hex(String.fromCharCode(key)), key); } if (obj.parent) { obj.parent.Send(String.fromCharCode(key)); } }
+
+ function _TermMoveUp(linecount) {
+ var x, y;
+ for (y = _scrollRegion[0]; y <= _scrollRegion[1] - linecount; y++) {
+ _tscreen[y] = _tscreen[y + linecount];
+ _scratt[y] = _scratt[y + linecount];
+ }
+ for (y = _scrollRegion[1] - linecount + 1; y <= _scrollRegion[1]; y++) {
+ _tscreen[y] = [];
+ _scratt[y] = [];
+ for (x = 0; x < obj.width; x++) {
+ _tscreen[y][x] = ' ';
+ _scratt[y][x] = (7 << 6);
+ }
+ }
+ }
+
+ obj.TermHandleKeys = function (e) {
+ if (!e.ctrlKey) {
+ if (e.which == 127) obj.TermSendKey(8);
+ else if (e.which == 13) { obj.TermSendKeys(obj.lineFeed); }
+ else if (e.which != 0) obj.TermSendKey(e.which);
+ return false;
+ }
+ if (e.preventDefault) e.preventDefault();
+ if (e.stopPropagation) e.stopPropagation();
+ }
+
+ obj.TermHandleKeyUp = function (e) {
+ if ((e.which != 8) && (e.which != 32) && (e.which != 9)) return true;
+ if (e.preventDefault) e.preventDefault();
+ if (e.stopPropagation) e.stopPropagation();
+ return false;
+ }
+
+ obj.TermHandleKeyDown = function (e) {
+ if ((e.which >= 65) && (e.which <= 90) && (e.ctrlKey == true)) {
+ obj.TermSendKey(e.which - 64);
+ if (e.preventDefault) e.preventDefault();
+ if (e.stopPropagation) e.stopPropagation();
+ return;
+ }
+ if (e.which == 27) { obj.TermSendKeys(String.fromCharCode(27)); return true; }; // ESC
+
+ if (_altKeypadMode == true) {
+ if (e.which == 37) { obj.TermSendKeys(String.fromCharCode(27, 79, 68)); return true; }; // Left
+ if (e.which == 38) { obj.TermSendKeys(String.fromCharCode(27, 79, 65)); return true; }; // Up
+ if (e.which == 39) { obj.TermSendKeys(String.fromCharCode(27, 79, 67)); return true; }; // Right
+ if (e.which == 40) { obj.TermSendKeys(String.fromCharCode(27, 79, 66)); return true; }; // Down
+ } else {
+ if (e.which == 37) { obj.TermSendKeys(String.fromCharCode(27, 91, 68)); return true; }; // Left
+ if (e.which == 38) { obj.TermSendKeys(String.fromCharCode(27, 91, 65)); return true; }; // Up
+ if (e.which == 39) { obj.TermSendKeys(String.fromCharCode(27, 91, 67)); return true; }; // Right
+ if (e.which == 40) { obj.TermSendKeys(String.fromCharCode(27, 91, 66)); return true; }; // Down
+ }
+
+ if (e.which == 33) { obj.TermSendKeys(String.fromCharCode(27, 91, 53, 126)); return true; }; // PageUp
+ if (e.which == 34) { obj.TermSendKeys(String.fromCharCode(27, 91, 54, 126)); return true; }; // PageDown
+ if (e.which == 35) { obj.TermSendKeys(String.fromCharCode(27, 91, 70)); return true; }; // End
+ if (e.which == 36) { obj.TermSendKeys(String.fromCharCode(27, 91, 72)); return true; }; // Home
+ if (e.which == 45) { obj.TermSendKeys(String.fromCharCode(27, 91, 50, 126)); return true; }; // Insert
+ if (e.which == 46) { obj.TermSendKeys(String.fromCharCode(27, 91, 51, 126)); return true; }; // Delete
+
+ if (e.which == 9) { obj.TermSendKeys("\t"); if (e.preventDefault) e.preventDefault(); if (e.stopPropagation) e.stopPropagation(); return true; }; // TAB
+
+ // F1 to F12 keys
+ // ###BEGIN###{Terminal-FxEnumation-All}
+ var fx0 = [80, 81, 119, 120, 116, 117, 113, 114, 112, 77];
+ var fx1 = [49, 50, 51, 52, 53, 54, 55, 56, 57, 48, 33, 64];
+ var fx2 = [80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91];
+ if (e.which > 111 & e.which < 124 && e.repeat == false) { // F1 to F12 keys
+ if (obj.fxEmulation == 0 && e.which < 122) { obj.TermSendKeys(String.fromCharCode(27, 91, 79, fx0[e.which - 112])); return true; } // 'Intel (F10 = ESC+[OM)'
+ if (obj.fxEmulation == 1) { obj.TermSendKeys(String.fromCharCode(27, fx1[e.which - 112])); return true; } // 'Alternate (F10 = ESC+0)'
+ if (obj.fxEmulation == 2) { obj.TermSendKeys(String.fromCharCode(27, 79, fx2[e.which - 112])); return true; } // 'VT100+ (F10 = ESC+[OY)'
+ }
+ // ###END###{Terminal-FxEnumation-All}
+ // ###BEGIN###{Terminal-FxEnumation-Intel}
+ var fx0 = [80, 81, 119, 120, 116, 117, 113, 114, 112, 77];
+ if (e.which > 111 & e.which < 122 && e.repeat == false) { obj.TermSendKeys(String.fromCharCode(27, 91, 79, fx0[e.which - 112])); return true; } // 'Intel (F10 = ESC+[OM)'
+ // ###END###{Terminal-FxEnumation-Intel}
+ // ###BEGIN###{Terminal-FxEnumation-Alternate}
+ var fx1 = [49, 50, 51, 52, 53, 54, 55, 56, 57, 48, 33, 64];
+ if (e.which > 111 & e.which < 124 && e.repeat == false) { obj.TermSendKeys(String.fromCharCode(27, fx1[e.which - 112])); return true; } // 'Alternate (F10 = ESC+0)'
+ // ###END###{Terminal-FxEnumation-Alternate}
+ // ###BEGIN###{Terminal-FxEnumation-VT100Plus}
+ var fx2 = [80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91];
+ if (e.which > 111 & e.which < 124 && e.repeat == false) { obj.TermSendKeys(String.fromCharCode(27, 79, fx2[e.which - 112])); return true; } // 'VT100+ (F10 = ESC+[OY)'
+ // ###END###{Terminal-FxEnumation-VT100Plus}
+
+ if (e.which != 8 && e.which != 32 && e.which != 9) return true;
+ obj.TermSendKey(e.which);
+ if (e.preventDefault) e.preventDefault();
+ if (e.stopPropagation) e.stopPropagation();
+ return false;
+ }
+
+ obj.recordLineTobackBuffer = function(y) {
+ var closetag = '', buf = '';
+ var r = obj.TermDrawLine(buf, y, closetag);
+ buf = r[0];
+ closetag = r[1];
+ scrollBackBuffer.push(buf + closetag + '
');
+ }
+
+ obj.TermDrawLine = function (buf, y, closetag) {
+ var newat, c, oldat = 1, x1, x2;
+ for (var x = 0; x < obj.width; ++x) {
+ newat = _scratt[y][x];
+ if (_termx == x && _termy == y && _cursorVisible) { newat |= _VTREVERSE; } // If this is the cursor location, reverse the color.
+ if (newat != oldat) {
+ buf += closetag;
+ closetag = '';
+ x1 = 6; x2 = 12;
+ if (newat & _VTREVERSE) { x1 = 12; x2 = 6; }
+ buf += '';
+ closetag = "" + closetag;
+ oldat = newat;
+ }
+
+ c = _tscreen[y][x];
+ switch (c) {
+ case '&': buf += '&'; break;
+ case '<': buf += '<'; break;
+ case '>': buf += '>'; break;
+ case ' ': buf += ' '; break;
+ default: buf += c; break;
+ }
+ }
+ return [buf, closetag];
+ }
+
+ obj.TermDraw = function() {
+ var closetag = '', buf = '';
+ for (var y = 0; y < obj.height; ++y) {
+ var r = obj.TermDrawLine(buf, y, closetag);
+ buf = r[0];
+ closetag = r[1];
+ if (y != (obj.height - 1)) buf += '
';
+ }
+
+ if (scrollBackBuffer.length > 800) { scrollBackBuffer = scrollBackBuffer.slice(scrollBackBuffer.length - 800); }
+ var backbuffer = scrollBackBuffer.join('');
+ obj.DivElement.innerHTML = "" + backbuffer + buf + closetag + "";
+ obj.DivElement.scrollTop = obj.DivElement.scrollHeight;
+ //if (obj.heightLock == 0) { setTimeout(obj.TermLockHeight, 10); }
+ }
+
+ /*
+ obj.TermLockHeight = function () {
+ obj.heightLock = obj.DivElement.clientHeight;
+ obj.DivElement.style['height'] = obj.DivElement.parentNode.style['height'] = obj.heightLock + 'px';
+ obj.DivElement.style['overflow-y'] = 'scroll';
+ }
+ */
+
+ obj.TermInit = function () { obj.TermResetScreen(); }
+
+ //obj.heightLock = 0;
+ //obj.DivElement.style['height'] = '';
+ if ((options != null) && (options.width != null) && (options.height != null)) { obj.Init(options.width, options.height); } else { obj.Init(); }
+ return obj;
+}
\ No newline at end of file
diff --git a/amt-wsman-0.2.0.js b/amt-wsman-0.2.0.js
new file mode 100644
index 0000000..7426aa9
--- /dev/null
+++ b/amt-wsman-0.2.0.js
@@ -0,0 +1,336 @@
+/**
+* @description Intel(r) AMT WSMAN Stack
+* @author Ylian Saint-Hilaire
+* @version v0.2.0
+*/
+
+// Construct a MeshServer object
+var WsmanStackCreateService = function (host, port, user, pass, tls, extra) {
+ var obj = {};
+ //obj.onDebugMessage = null; // Set to a function if you want to get debug messages.
+ obj.NextMessageId = 1; // Next message number, used to label WSMAN calls.
+ obj.Address = '/wsman';
+ obj.comm = CreateWsmanComm(host, port, user, pass, tls, extra);
+
+ obj.PerformAjax = function (postdata, callback, tag, pri, namespaces) {
+ if (namespaces == null) namespaces = '';
+ obj.comm.PerformAjax('' + postdata, function (data, status, tag) {
+ if (status != 200) { callback(obj, null, { Header: { HttpError: status } }, status, tag); return; }
+ var wsresponse = obj.ParseWsman(data);
+ if (!wsresponse || wsresponse == null) { callback(obj, null, { Header: { HttpError: status } }, 601, tag); } else { callback(obj, wsresponse.Header["ResourceURI"], wsresponse, 200, tag); }
+ }, tag, pri);
+ }
+
+ // Private method
+ //obj.Debug = function (msg) { /*console.log(msg);*/ }
+
+ // Cancel all pending queries with given status
+ obj.CancelAllQueries = function (s) { obj.comm.CancelAllQueries(s); }
+
+ // Get the last element of a URI string
+ obj.GetNameFromUrl = function (resuri) {
+ var x = resuri.lastIndexOf("/");
+ return (x == -1)?resuri:resuri.substring(x + 1);
+ }
+
+ // Perform a WSMAN Subscribe operation
+ obj.ExecSubscribe = function (resuri, delivery, url, callback, tag, pri, selectors, opaque, user, pass) {
+ var digest = "", digest2 = "", opaque = "";
+ if (user != null && pass != null) { digest = 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#UsernameToken' + user + '' + pass + ''; digest2 = ''; }
+ if (opaque != null) { opaque = '' + opaque + ''; }
+ if (delivery == 'PushWithAck') { delivery = 'dmtf.org/wbem/wsman/1/wsman/PushWithAck'; } else if (delivery == 'Push') { delivery = 'xmlsoap.org/ws/2004/08/eventing/DeliveryModes/Push'; }
+ var data = "http://schemas.xmlsoap.org/ws/2004/08/eventing/Subscribe" + obj.Address + "" + resuri + "" + (obj.NextMessageId++) + "http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous" + _PutObjToSelectorsXml(selectors) + digest + '' + url + '' + opaque + '' + digest2 + '';
+ obj.PerformAjax(data + "", callback, tag, pri, 'xmlns:e="http://schemas.xmlsoap.org/ws/2004/08/eventing" xmlns:m="http://x.com"');
+ }
+
+ // Perform a WSMAN UnSubscribe operation
+ obj.ExecUnSubscribe = function (resuri, callback, tag, pri, selectors) {
+ var data = "http://schemas.xmlsoap.org/ws/2004/08/eventing/Unsubscribe" + obj.Address + "" + resuri + "" + (obj.NextMessageId++) + "http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous" + _PutObjToSelectorsXml(selectors) + '';
+ obj.PerformAjax(data + "", callback, tag, pri, 'xmlns:e="http://schemas.xmlsoap.org/ws/2004/08/eventing"');
+ }
+
+ // Perform a WSMAN PUT operation
+ obj.ExecPut = function (resuri, putobj, callback, tag, pri, selectors) {
+ var data = "http://schemas.xmlsoap.org/ws/2004/09/transfer/Put" + obj.Address + "" + resuri + "" + (obj.NextMessageId++) + "http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymousPT60.000S" + _PutObjToSelectorsXml(selectors) + '' + _PutObjToBodyXml(resuri, putobj);
+ obj.PerformAjax(data + "", callback, tag, pri);
+ }
+
+ // Perform a WSMAN CREATE operation
+ obj.ExecCreate = function (resuri, putobj, callback, tag, pri, selectors) {
+ var objname = obj.GetNameFromUrl(resuri);
+ var data = "http://schemas.xmlsoap.org/ws/2004/09/transfer/Create" + obj.Address + "" + resuri + "" + (obj.NextMessageId++) + "http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymousPT60S" + _PutObjToSelectorsXml(selectors) + "";
+ for (var n in putobj) { data += "" + putobj[n] + "" }
+ obj.PerformAjax(data + "", callback, tag, pri);
+ }
+
+ // Perform a WSMAN DELETE operation
+ obj.ExecDelete = function (resuri, putobj, callback, tag, pri) {
+ var data = "http://schemas.xmlsoap.org/ws/2004/09/transfer/Delete" + obj.Address + "" + resuri + "" + (obj.NextMessageId++) + "http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymousPT60S" + _PutObjToSelectorsXml(putobj) + "";
+ obj.PerformAjax(data, callback, tag, pri);
+ }
+
+ // Perform a WSMAN GET operation
+ obj.ExecGet = function (resuri, callback, tag, pri) {
+ obj.PerformAjax("http://schemas.xmlsoap.org/ws/2004/09/transfer/Get" + obj.Address + "" + resuri + "" + (obj.NextMessageId++) + "http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymousPT60S", callback, tag, pri);
+ }
+
+ // Perform a WSMAN method call operation
+ obj.ExecMethod = function (resuri, method, args, callback, tag, pri, selectors) {
+ var argsxml = "";
+ for (var i in args) { if (args[i] != null) { if (Array.isArray(args[i])) { for (var x in args[i]) { argsxml += "" + args[i][x] + ""; } } else { argsxml += "" + args[i] + ""; } } }
+ obj.ExecMethodXml(resuri, method, argsxml, callback, tag, pri, selectors);
+ }
+
+ // Perform a WSMAN method call operation. The arguments are already formatted in XML.
+ obj.ExecMethodXml = function (resuri, method, argsxml, callback, tag, pri, selectors) {
+ obj.PerformAjax(resuri + "/" + method + "" + obj.Address + "" + resuri + "" + (obj.NextMessageId++) + "http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymousPT60S" + _PutObjToSelectorsXml(selectors) + "
" + argsxml + "", callback, tag, pri);
+ }
+
+ // Perform a WSMAN ENUM operation
+ obj.ExecEnum = function (resuri, callback, tag, pri) {
+ obj.PerformAjax("http://schemas.xmlsoap.org/ws/2004/09/enumeration/Enumerate" + obj.Address + "" + resuri + "" + (obj.NextMessageId++) + "http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymousPT60S", callback, tag, pri);
+ }
+
+ // Perform a WSMAN PULL operation
+ obj.ExecPull = function (resuri, enumctx, callback, tag, pri) {
+ obj.PerformAjax("http://schemas.xmlsoap.org/ws/2004/09/enumeration/Pull" + obj.Address + "" + resuri + "" + (obj.NextMessageId++) + "http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymousPT60S" + enumctx + "", callback, tag, pri); // --99999999--
+ }
+
+ // Private method
+ obj.ParseWsman = function (xml) {
+ try {
+ if (!xml.childNodes) xml = _turnToXml(xml);
+ var r = { Header:{} }, header = xml.getElementsByTagName("Header")[0], t;
+ if (!header) header = xml.getElementsByTagName("a:Header")[0];
+ if (!header) return null;
+ for (var i = 0; i < header.childNodes.length; i++) {
+ var child = header.childNodes[i];
+ r.Header[child.localName] = child.textContent;
+ }
+ var body = xml.getElementsByTagName("Body")[0];
+ if (!body) body = xml.getElementsByTagName("a:Body")[0];
+ if (!body) return null;
+ if (body.childNodes.length > 0) {
+ t = body.childNodes[0].localName;
+ if (t.indexOf("_OUTPUT") == t.length - 7) { t = t.substring(0, t.length - 7); }
+ r.Header['Method'] = t;
+ r.Body = _ParseWsmanRec(body.childNodes[0]);
+ }
+ return r;
+ } catch (e) {
+ console.log("Unable to parse XML: " + xml);
+ return null;
+ }
+ }
+
+ // Private method
+ function _ParseWsmanRec(node) {
+ var data, r = {};
+ for (var i = 0; i < node.childNodes.length; i++) {
+ var child = node.childNodes[i];
+ if ((child.childElementCount == null) || (child.childElementCount == 0)) { data = child.textContent; } else { data = _ParseWsmanRec(child); }
+ if (data == 'true') data = true; // Convert 'true' into true
+ if (data == 'false') data = false; // Convert 'false' into false
+ if ((parseInt(data) + '') === data) data = parseInt(data); // Convert integers
+
+ var childObj = data;
+ if ((child.attributes != null) && (child.attributes.length > 0)) {
+ childObj = { 'Value': data };
+ for(var j = 0; j < child.attributes.length; j++) {
+ childObj['@' + child.attributes[j].name] = child.attributes[j].value;
+ }
+ }
+
+ if (r[child.localName] instanceof Array) { r[child.localName].push(childObj); }
+ else if (r[child.localName] == null) { r[child.localName] = childObj; }
+ else { r[child.localName] = [r[child.localName], childObj]; }
+ }
+ return r;
+ }
+
+ function _PutObjToBodyXml(resuri, putObj) {
+ if (!resuri || putObj == null) return '';
+ var objname = obj.GetNameFromUrl(resuri);
+ var result = '';
+
+ for (var prop in putObj) {
+ if (!putObj.hasOwnProperty(prop) || prop.indexOf('__') === 0 || prop.indexOf('@') === 0) continue;
+ if (putObj[prop] == null || typeof putObj[prop] === 'function') continue;
+ if (typeof putObj[prop] === 'object' && putObj[prop]['ReferenceParameters']) {
+ result += '' + putObj[prop].Address + '' + putObj[prop]['ReferenceParameters']["ResourceURI"] + '';
+ var selectorArray = putObj[prop]['ReferenceParameters']['SelectorSet']['Selector'];
+ if (Array.isArray(selectorArray)) {
+ for (var i=0; i< selectorArray.length; i++) {
+ result += '' + selectorArray[i]['Value'] + '';
+ }
+ }
+ else {
+ result += '' + selectorArray['Value'] + '';
+ }
+ result += '';
+ }
+ else {
+ if (Array.isArray(putObj[prop])) {
+ for (var i = 0; i < putObj[prop].length; i++) {
+ result += '' + putObj[prop][i].toString() + '';
+ }
+ } else {
+ result += '' + putObj[prop].toString() + '';
+ }
+ }
+ }
+
+ result += '';
+ return result;
+ }
+
+ /*
+ convert
+ { @Name: 'InstanceID', @AttrName: 'Attribute Value'}
+ into
+ ' Name="InstanceID" AttrName="Attribute Value" '
+ */
+ function _ObjectToXmlAttributes(objWithAttributes) {
+ if(!objWithAttributes) return '';
+ var result = '';
+ for (var propName in objWithAttributes) {
+ if (!objWithAttributes.hasOwnProperty(propName) || propName.indexOf('@') !== 0) continue;
+ result += ' ' + propName.substring(1) + '="' + objWithAttributes[propName] + '"';
+ }
+ return result;
+ }
+
+ function _PutObjToSelectorsXml(selectorSet) {
+ if (!selectorSet) return '';
+ if (typeof selectorSet == 'string') return selectorSet;
+ if (selectorSet['InstanceID']) return "" + selectorSet['InstanceID'] + "";
+ var result = '';
+ for(var propName in selectorSet) {
+ if (!selectorSet.hasOwnProperty(propName)) continue;
+ result += '';
+ if (selectorSet[propName]['ReferenceParameters']) {
+ result += '';
+ result += '' + selectorSet[propName]['Address'] + '' + selectorSet[propName]['ReferenceParameters']['ResourceURI'] + '';
+ var selectorArray = selectorSet[propName]['ReferenceParameters']['SelectorSet']['Selector'];
+ if (Array.isArray(selectorArray)) {
+ for (var i = 0; i < selectorArray.length; i++) {
+ result += '' + selectorArray[i]['Value'] + '';
+ }
+ }
+ else {
+ result += '' + selectorArray['Value'] + '';
+ }
+ result += '';
+ } else {
+ result += selectorSet[propName];
+ }
+ result += '';
+ }
+ result += '';
+ return result;
+ }
+
+ function _turnToXml(text) {
+ // ###BEGIN###{!Mode-MeshCentral2}
+ // NodeJS detection
+ var isNode = new Function("try {return this===global;}catch(e){return false;}");
+ if (isNode()) {
+ var XDOMParser = require('xmldom').DOMParser;
+ return new XDOMParser().parseFromString(text, "text/xml");
+ }
+ // ###END###{!Mode-MeshCentral2}
+ if (window.DOMParser) {
+ return new DOMParser().parseFromString(text, "text/xml");
+ } else {
+ // Internet Explorer
+ var xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
+ xmlDoc.async = false;
+ xmlDoc.loadXML(text);
+ return xmlDoc;
+ }
+ }
+
+ /*
+ // This is a drop-in replacement to _turnToXml() that works without xml parser dependency.
+ Object.defineProperty(Array.prototype, "peek", { value: function () { return (this.length > 0 ? this[this.length - 1] : null); } });
+ function _treeBuilder() {
+ this.tree = [];
+ this.push = function (element) { this.tree.push(element); };
+ this.pop = function () { var element = this.tree.pop(); if (this.tree.length > 0) { var x = this.tree.peek(); x.childNodes.push(element); x.childElementCount = x.childNodes.length; } return (element); };
+ this.peek = function () { return (this.tree.peek()); }
+ this.addNamespace = function (prefix, namespace) { this.tree.peek().nsTable[prefix] = namespace; if (this.tree.peek().attributes.length > 0) { for (var i = 0; i < this.tree.peek().attributes; ++i) { var a = this.tree.peek().attributes[i]; if (prefix == '*' && a.name == a.localName) { a.namespace = namespace; } else if (prefix != '*' && a.name != a.localName) { var pfx = a.name.split(':')[0]; if (pfx == prefix) { a.namespace = namespace; } } } } }
+ this.getNamespace = function (prefix) { for (var i = this.tree.length - 1; i >= 0; --i) { if (this.tree[i].nsTable[prefix] != null) { return (this.tree[i].nsTable[prefix]); } } return null; }
+ }
+ function _turnToXml(text) { if (text == null) return null; return ({ childNodes: [_turnToXmlRec(text)], getElementsByTagName: _getElementsByTagName, getChildElementsByTagName: _getChildElementsByTagName, getElementsByTagNameNS: _getElementsByTagNameNS }); }
+ function _getElementsByTagNameNS(ns, name) { var ret = []; _xmlTraverseAllRec(this.childNodes, function (node) { if (node.localName == name && (node.namespace == ns || ns == '*')) { ret.push(node); } }); return ret; }
+ function _getElementsByTagName(name) { var ret = []; _xmlTraverseAllRec(this.childNodes, function (node) { if (node.localName == name) { ret.push(node); } }); return ret; }
+ function _getChildElementsByTagName(name) { var ret = []; if (this.childNodes != null) { for (var node in this.childNodes) { if (this.childNodes[node].localName == name) { ret.push(this.childNodes[node]); } } } return (ret); }
+ function _getChildElementsByTagNameNS(ns, name) { var ret = []; if (this.childNodes != null) { for (var node in this.childNodes) { if (this.childNodes[node].localName == name && (ns == '*' || this.childNodes[node].namespace == ns)) { ret.push(this.childNodes[node]); } } } return (ret); }
+ function _xmlTraverseAllRec(nodes, func) { for (var i in nodes) { func(nodes[i]); if (nodes[i].childNodes) { _xmlTraverseAllRec(nodes[i].childNodes, func); } } }
+ function _turnToXmlRec(text) {
+ var elementStack = new _treeBuilder(), lastElement = null, x1 = text.split('<'), ret = [], element = null, currentElementName = null;
+ for (var i in x1) {
+ var x2 = x1[i].split('>'), x3 = x2[0].split(' '), elementName = x3[0];
+ if ((elementName.length > 0) && (elementName[0] != '?')) {
+ if (elementName[0] != '/') {
+ var attributes = [], localName, localname2 = elementName.split(' ')[0].split(':'), localName = (localname2.length > 1) ? localname2[1] : localname2[0];
+ Object.defineProperty(attributes, "get",
+ {
+ value: function () {
+ if (arguments.length == 1) {
+ for (var a in this) { if (this[a].name == arguments[0]) { return (this[a]); } }
+ }
+ else if (arguments.length == 2) {
+ for (var a in this) { if (this[a].name == arguments[1] && (arguments[0] == '*' || this[a].namespace == arguments[0])) { return (this[a]); } }
+ }
+ else {
+ throw ('attributes.get(): Invalid number of parameters');
+ }
+ }
+ });
+ elementStack.push({ name: elementName, localName: localName, getChildElementsByTagName: _getChildElementsByTagName, getElementsByTagNameNS: _getElementsByTagNameNS, getChildElementsByTagNameNS: _getChildElementsByTagNameNS, attributes: attributes, childNodes: [], nsTable: {} });
+ // Parse Attributes
+ if (x3.length > 0) {
+ var skip = false;
+ for (var j in x3) {
+ if (x3[j] == '/') {
+ // This is an empty Element
+ elementStack.peek().namespace = elementStack.peek().name == elementStack.peek().localName ? elementStack.getNamespace('*') : elementStack.getNamespace(elementStack.peek().name.substring(0, elementStack.peek().name.indexOf(':')));
+ elementStack.peek().textContent = '';
+ lastElement = elementStack.pop();
+ skip = true;
+ break;
+ }
+ var k = x3[j].indexOf('=');
+ if (k > 0) {
+ var attrName = x3[j].substring(0, k);
+ var attrValue = x3[j].substring(k + 2, x3[j].length - 1);
+ var attrNS = elementStack.getNamespace('*');
+
+ if (attrName == 'xmlns') {
+ elementStack.addNamespace('*', attrValue);
+ attrNS = attrValue;
+ } else if (attrName.startsWith('xmlns:')) {
+ elementStack.addNamespace(attrName.substring(6), attrValue);
+ } else {
+ var ax = attrName.split(':');
+ if (ax.length == 2) { attrName = ax[1]; attrNS = elementStack.getNamespace(ax[0]); }
+ }
+ var x = { name: attrName, value: attrValue }
+ if (attrNS != null) x.namespace = attrNS;
+ elementStack.peek().attributes.push(x);
+ }
+ }
+ if (skip) { continue; }
+ }
+ elementStack.peek().namespace = elementStack.peek().name == elementStack.peek().localName ? elementStack.getNamespace('*') : elementStack.getNamespace(elementStack.peek().name.substring(0, elementStack.peek().name.indexOf(':')));
+ if (x2[1]) { elementStack.peek().textContent = x2[1]; }
+ } else { lastElement = elementStack.pop(); }
+ }
+ }
+ return lastElement;
+ }
+ */
+
+ return obj;
+}
diff --git a/amt-wsman-ajax-0.2.0.js b/amt-wsman-ajax-0.2.0.js
new file mode 100644
index 0000000..7cca880
--- /dev/null
+++ b/amt-wsman-ajax-0.2.0.js
@@ -0,0 +1,95 @@
+/**
+* @description WSMAN communication using browser AJAX
+* @author Ylian Saint-Hilaire
+* @version v0.2.0c
+*/
+
+// Construct a WSMAN communication object
+var CreateWsmanComm = function (url) {
+ var obj = {};
+ obj.PendingAjax = []; // List of pending AJAX calls. When one frees up, another will start.
+ obj.ActiveAjaxCount = 0; // Number of currently active AJAX calls
+ obj.MaxActiveAjaxCount = 1; // Maximum number of activate AJAX calls at the same time.
+ obj.FailAllError = 0; // Set this to non-zero to fail all AJAX calls with that error status, 999 causes responses to be silent.
+ obj.Url = url;
+
+ // Private method
+ // pri = priority, if set to 1, the call is high priority and put on top of the stack.
+ obj.PerformAjax = function (postdata, callback, tag, pri, url, action) {
+ if ((obj.ActiveAjaxCount == 0 || ((obj.ActiveAjaxCount < obj.MaxActiveAjaxCount) && (obj.challengeParams != null))) && obj.PendingAjax.length == 0) {
+ // There are no pending AJAX calls, perform the call now.
+ obj.PerformAjaxEx(postdata, callback, tag, url, action);
+ } else {
+ // If this is a high priority call, put this call in front of the array, otherwise put it in the back.
+ if (pri == 1) { obj.PendingAjax.unshift([postdata, callback, tag, url, action]); } else { obj.PendingAjax.push([postdata, callback, tag, url, action]); }
+ }
+ }
+
+ // Private method
+ obj.PerformNextAjax = function () {
+ if (obj.ActiveAjaxCount >= obj.MaxActiveAjaxCount || obj.PendingAjax.length == 0) return;
+ var x = obj.PendingAjax.shift();
+ obj.PerformAjaxEx(x[0], x[1], x[2], x[3], x[4]);
+ obj.PerformNextAjax();
+ }
+
+ // Private method
+ obj.PerformAjaxEx = function (postdata, callback, tag, url, action) {
+ if (obj.FailAllError != 0) { if (obj.FailAllError != 999) { obj.gotNextMessagesError({ status: obj.FailAllError }, 'error', null, [postdata, callback, tag]); } return; }
+ // console.log("SEND: " + postdata); // DEBUG
+
+ // We are in a AJAX browser environment
+ obj.ActiveAjaxCount++;
+ if (!postdata) { postdata = ''; }
+ var xdr = null; // TODO: See if we should re-use this object and if we do, when should we do it.
+ try { xdr = new XDomainRequest(); } catch (e) { }
+ if (!xdr) xdr = new XMLHttpRequest();
+ xdr.open(action ? action : "POST", url ? url : obj.Url);
+ xdr.timeout = 15000;
+ xdr.onload = function () { obj.gotNextMessages(xdr.responseText, 'success', xdr, [postdata, callback, tag]); };
+ xdr.onerror = function () { obj.gotNextMessagesError(xdr, 'error', null, [postdata, callback, tag]); };
+ xdr.ontimeout = function () { obj.gotNextMessagesError(xdr, 'error', null, [postdata, callback, tag]); };
+ //xdr.send(postdata); // Works for text only, no binary.
+
+ // Send POST body, this work with binary.
+ if (urlvars && urlvars['wsmantrace']) { console.log("WSMAN-SEND(" + postdata.length + "): " + postdata); }
+ var b = new Uint8Array(postdata.length);
+ for (var i = 0; i < postdata.length; ++i) { b[i] = postdata.charCodeAt(i); }
+ xdr.send(b);
+
+ return xdr;
+ }
+
+ // AJAX specific private method
+ obj.pendingAjaxCall = [];
+
+ // Private method
+ obj.gotNextMessages = function (data, status, request, callArgs) {
+ if (urlvars && urlvars['wsmantrace']) { console.log("WSMAN-RECV(" + data.length + "): " + data); }
+ obj.ActiveAjaxCount--;
+ if (obj.FailAllError == 999) return;
+ // console.log("RECV: " + data); // DEBUG
+ if (obj.FailAllError != 0) { callArgs[1](null, obj.FailAllError, callArgs[2]); return; }
+ if (request.status != 200) { callArgs[1](null, request.status, callArgs[2]); obj.PerformNextAjax(); return; }
+ callArgs[1](data, 200, callArgs[2]);
+ obj.PerformNextAjax();
+ }
+
+ // Private method
+ obj.gotNextMessagesError = function (request, status, errorThrown, callArgs) {
+ obj.ActiveAjaxCount--;
+ if (obj.FailAllError == 999) return;
+ if (obj.FailAllError != 0) { callArgs[1](null, obj.FailAllError, callArgs[2]); return; }
+ // if (s != 200) { console.log("ERROR, status=" + status + "\r\n\r\nreq=" + callArgs[0]); } // Debug: Display the request & response if something did not work.
+ if (obj.FailAllError != 999) { callArgs[1]({ Header: { HttpError: request.status } }, request.status, callArgs[2]); }
+ obj.PerformNextAjax();
+ }
+
+ // Cancel all pending queries with given status
+ obj.CancelAllQueries = function (s) {
+ while (obj.PendingAjax.length > 0) { var x = obj.PendingAjax.shift(); x[1](null, s, x[2]); }
+ }
+
+ return obj;
+}
+
diff --git a/amt-wsman-node-0.2.0.js b/amt-wsman-node-0.2.0.js
new file mode 100644
index 0000000..4a633cb
--- /dev/null
+++ b/amt-wsman-node-0.2.0.js
@@ -0,0 +1,392 @@
+/**
+* @description Intel(r) AMT WSMAN communication using Node.js TLS
+* @author Ylian Saint-Hilaire
+* @version v0.2.0b
+*/
+
+// Construct a MeshServer object
+var CreateWsmanComm = function (host, port, user, pass, tls, tlsoptions) {
+ //console.log('CreateWsmanComm', host, port, user, pass, tls, tlsoptions);
+
+ var obj = {};
+ obj.PendingAjax = []; // List of pending AJAX calls. When one frees up, another will start.
+ obj.ActiveAjaxCount = 0; // Number of currently active AJAX calls
+ obj.MaxActiveAjaxCount = 1; // Maximum number of activate AJAX calls at the same time.
+ obj.FailAllError = 0; // Set this to non-zero to fail all AJAX calls with that error status, 999 causes responses to be silent.
+ obj.challengeParams = null;
+ obj.noncecounter = 1;
+ obj.authcounter = 0;
+
+ obj.Address = '/wsman';
+ obj.challengeParams = null;
+ obj.noncecounter = 1;
+ obj.authcounter = 0;
+ obj.cnonce = Math.random().toString(36).substring(7); // Generate a random client nonce
+
+ obj.net = require('net');
+ obj.tls = require('tls');
+ obj.crypto = require('crypto');
+ obj.constants = require('constants');
+ obj.socket = null;
+ obj.socketState = 0;
+ obj.kerberosDone = 0;
+ obj.amtVersion = null;
+
+ obj.host = host;
+ obj.port = port;
+ obj.user = user;
+ obj.pass = pass;
+ obj.xtls = tls;
+ obj.xtlsoptions = tlsoptions;
+ obj.xtlsFingerprint;
+ obj.xtlsCertificate = null;
+ obj.xtlsCheck = 0; // 0 = No TLS, 1 = CA Checked, 2 = Pinned, 3 = Untrusted
+ obj.xtlsSkipHostCheck = 0;
+ obj.xtlsMethod = 0;
+ obj.xtlsDataReceived = false;
+ obj.digestRealmMatch = null;
+ obj.digestRealm = null;
+
+ // Private method
+ //obj.Debug = function (msg) { console.log(msg); }
+
+ // Private method
+ // pri = priority, if set to 1, the call is high priority and put on top of the stack.
+ obj.PerformAjax = function (postdata, callback, tag, pri, url, action) {
+ if ((obj.ActiveAjaxCount == 0 || ((obj.ActiveAjaxCount < obj.MaxActiveAjaxCount) && (obj.challengeParams != null))) && obj.PendingAjax.length == 0) {
+ // There are no pending AJAX calls, perform the call now.
+ obj.PerformAjaxEx(postdata, callback, tag, url, action);
+ } else {
+ // If this is a high priority call, put this call in front of the array, otherwise put it in the back.
+ if (pri == 1) { obj.PendingAjax.unshift([postdata, callback, tag, url, action]); } else { obj.PendingAjax.push([postdata, callback, tag, url, action]); }
+ }
+ }
+
+ // Private method
+ obj.PerformNextAjax = function () {
+ if (obj.ActiveAjaxCount >= obj.MaxActiveAjaxCount || obj.PendingAjax.length == 0) return;
+ var x = obj.PendingAjax.shift();
+ obj.PerformAjaxEx(x[0], x[1], x[2], x[3], x[4]);
+ obj.PerformNextAjax();
+ }
+
+ // Private method
+ obj.PerformAjaxEx = function (postdata, callback, tag, url, action) {
+ if (obj.FailAllError != 0) { obj.gotNextMessagesError({ status: obj.FailAllError }, 'error', null, [postdata, callback, tag, url, action]); return; }
+ if (!postdata) postdata = '';
+ //obj.Debug("SEND: " + postdata); // DEBUG
+
+ obj.ActiveAjaxCount++;
+ return obj.PerformAjaxExNodeJS(postdata, callback, tag, url, action);
+ }
+
+ // NODE.js specific private method
+ obj.pendingAjaxCall = [];
+
+ // NODE.js specific private method
+ obj.PerformAjaxExNodeJS = function (postdata, callback, tag, url, action) { obj.PerformAjaxExNodeJS2(postdata, callback, tag, url, action, 5); }
+
+ // NODE.js specific private method
+ obj.PerformAjaxExNodeJS2 = function (postdata, callback, tag, url, action, retry) {
+ if (retry <= 0 || obj.FailAllError != 0) {
+ // Too many retry, fail here.
+ obj.ActiveAjaxCount--;
+ if (obj.FailAllError != 999) obj.gotNextMessages(null, 'error', { status: ((obj.FailAllError == 0) ? 408 : obj.FailAllError) }, [postdata, callback, tag, url, action]); // 408 is timeout error
+ obj.PerformNextAjax();
+ return;
+ }
+ obj.pendingAjaxCall.push([postdata, callback, tag, url, action, retry]);
+ if (obj.socketState == 0) { obj.xxConnectHttpSocket(); }
+ else if (obj.socketState == 2) { obj.sendRequest(postdata, url, action); }
+ }
+
+ // NODE.js specific private method
+ obj.sendRequest = function (postdata, url, action) {
+ url = url ? url : '/wsman';
+ action = action ? action : 'POST';
+ var h = action + ' ' + url + ' HTTP/1.1\r\n';
+ if (obj.challengeParams != null) {
+ obj.digestRealm = obj.challengeParams['realm'];
+ if (obj.digestRealmMatch && (obj.digestRealm != obj.digestRealmMatch)) {
+ obj.FailAllError = 997; // Cause all new responses to be silent. 997 = Digest Realm check error
+ obj.CancelAllQueries(997);
+ return;
+ }
+ }
+ if ((obj.user == '*') && (kerberos != null)) {
+ // Kerberos Auth
+ if (obj.kerberosDone == 0) {
+ var ticketName = 'HTTP' + ((obj.tls == 1) ? 'S' : '') + '/' + ((obj.pass == '') ? (obj.host + ':' + obj.port) : obj.pass);
+ // Ask for the new Kerberos ticket
+ //console.log('kerberos.getTicket', ticketName);
+ var ticketReturn = kerberos.getTicket(ticketName);
+ if (ticketReturn.returnCode == 0 || ticketReturn.returnCode == 0x90312) {
+ h += 'Authorization: Negotiate ' + ticketReturn.ticket + '\r\n';
+ if (process.platform.indexOf('win') >= 0) {
+ // Clear kerberos tickets on both 32 and 64bit Windows platforms
+ try { require('child_process').exec('%windir%\\system32\\klist purge', function (error, stdout, stderr) { if (error) { require('child_process').exec('%windir%\\sysnative\\klist purge', function (error, stdout, stderr) { if (error) { console.error('Unable to purge kerberos tickets'); } }); } }); } catch (e) { console.log(e); }
+ }
+ } else {
+ console.log('Unexpected Kerberos error code: ' + ticketReturn.returnCode);
+ }
+ obj.kerberosDone = 1;
+ }
+ } else if (obj.challengeParams != null) {
+ var response = hex_md5(hex_md5(obj.user + ':' + obj.challengeParams['realm'] + ':' + obj.pass) + ':' + obj.challengeParams['nonce'] + ':' + obj.noncecounter + ':' + obj.cnonce + ':' + obj.challengeParams['qop'] + ':' + hex_md5(action + ':' + url + ((obj.challengeParams['qop'] == 'auth-int')?(':' + hex_md5(postdata)):'')));
+ h += 'Authorization: ' + obj.renderDigest({ 'username': obj.user, 'realm': obj.challengeParams['realm'], 'nonce': obj.challengeParams['nonce'], 'uri': url, 'qop': obj.challengeParams['qop'], 'response': response, 'nc': obj.noncecounter++, 'cnonce': obj.cnonce }) + '\r\n';
+ }
+ h += 'Host: ' + obj.host + ':' + obj.port + '\r\nContent-Length: ' + postdata.length + '\r\n\r\n' + postdata; // Use Content-Length
+ //h += 'Host: ' + obj.host + ':' + obj.port + '\r\nTransfer-Encoding: chunked\r\n\r\n' + postdata.length.toString(16).toUpperCase() + '\r\n' + postdata + '\r\n0\r\n\r\n'; // Use Chunked-Encoding
+ obj.xxSend(h);
+ //console.log("SEND: " + h); // Display send packet
+ }
+
+ // Parse the HTTP digest header and return a list of key & values.
+ obj.parseDigest = function (header) { return correctedQuoteSplit(header.substring(7)).reduce(function (obj, s) { var parts = s.trim().split('='); obj[parts[0]] = parts[1].replace(new RegExp('\"', 'g'), ''); return obj; }, {}) }
+
+ // Split a string on quotes but do not do it when in quotes
+ function correctedQuoteSplit(str) { return str.split(',').reduce(function (a, c) { if (a.ic) { a.st[a.st.length - 1] += ',' + c } else { a.st.push(c) } if (c.split('"').length % 2 == 0) { a.ic = !a.ic } return a; }, { st: [], ic: false }).st }
+
+ // NODE.js specific private method
+ obj.renderDigest = function (params) {
+ var paramsnames = [];
+ for (i in params) { paramsnames.push(i); }
+ return 'Digest ' + paramsnames.reduce(function (s1, ii) { return s1 + ',' + ii + '="' + params[ii] + '"' }, '').substring(1);
+ }
+
+ // NODE.js specific private method
+ obj.xxConnectHttpSocket = function () {
+ //obj.Debug("xxConnectHttpSocket");
+ obj.socketParseState = 0;
+ obj.socketAccumulator = '';
+ obj.socketHeader = null;
+ obj.socketData = '';
+ obj.socketState = 1;
+ obj.kerberosDone = 0;
+
+ if (obj.xtlsoptions && obj.xtlsoptions.meshServerConnect) {
+ // Use the websocket wrapper to connect to MeshServer server
+ obj.socket = CreateWebSocketWrapper(obj.xtlsoptions.host, obj.xtlsoptions.port, '/webrelay.ashx?user=' + encodeURIComponent(obj.xtlsoptions.username) + '&pass=' + encodeURIComponent(obj.xtlsoptions.password) + '&host=' + encodeURIComponent(obj.host) + '&p=1&tls1only=' + obj.xtlsMethod, obj.xtlsoptions.xtlsFingerprint);
+ obj.socket.setEncoding('binary');
+ obj.socket.setTimeout(6000); // Set socket idle timeout
+ obj.socket.ondata = obj.xxOnSocketData;
+ obj.socket.onclose = function () { if (obj.xtlsDataReceived == false) { obj.xtlsMethod = 1 - obj.xtlsMethod; } obj.xxOnSocketClosed(); }
+ obj.socket.ontimeout = function () { if (obj.xtlsDataReceived == false) { obj.xtlsMethod = 1 - obj.xtlsMethod; } obj.xxOnSocketClosed(); }
+ obj.socket.connect(obj.xxOnSocketConnected);
+ } else if (obj.xtls != 1) {
+ // Connect without TLS
+ obj.socket = new obj.net.Socket();
+ obj.socket.setEncoding('binary');
+ obj.socket.setTimeout(6000); // Set socket idle timeout
+ obj.socket.on('data', obj.xxOnSocketData);
+ obj.socket.on('close', obj.xxOnSocketClosed);
+ obj.socket.on('timeout', obj.xxOnSocketClosed);
+ obj.socket.connect(obj.port, obj.host, obj.xxOnSocketConnected);
+ } else {
+ // Connect with TLS
+ var options = { secureProtocol: ((obj.xtlsMethod == 0) ? 'SSLv23_method' : 'TLSv1_method'), ciphers: 'RSA+AES:!aNULL:!MD5:!DSS', secureOptions: obj.constants.SSL_OP_NO_SSLv2 | obj.constants.SSL_OP_NO_SSLv3 | obj.constants.SSL_OP_NO_COMPRESSION | obj.constants.SSL_OP_CIPHER_SERVER_PREFERENCE, rejectUnauthorized: false };
+ if (obj.xtlsoptions) {
+ if (obj.xtlsoptions.ca) options.ca = obj.xtlsoptions.ca;
+ if (obj.xtlsoptions.cert) options.cert = obj.xtlsoptions.cert;
+ if (obj.xtlsoptions.key) options.key = obj.xtlsoptions.key;
+ obj.xtlsoptions = options;
+ }
+ obj.socket = obj.tls.connect(obj.port, obj.host, obj.xtlsoptions, obj.xxOnSocketConnected);
+ obj.socket.setEncoding('binary');
+ obj.socket.setTimeout(6000); // Set socket idle timeout
+ obj.socket.on('data', obj.xxOnSocketData);
+ obj.socket.on('close', obj.xxOnSocketClosed);
+ obj.socket.on('timeout', obj.xxOnSocketClosed);
+ obj.socket.on('error', function (e) { if (e.message && e.message.indexOf('sslv3 alert bad record mac') >= 0) { obj.xtlsMethod = 1 - obj.xtlsMethod; } });
+ }
+ obj.socket.setNoDelay(true); // Disable nagle. We will encode each WSMAN request as a single send block and want to send it at once. This may help Intel AMT handle pipelining?
+ }
+
+ // Get the certificate of Intel AMT
+ obj.getPeerCertificate = function () { if (obj.xtls == 1) { return obj.socket.getPeerCertificate(); } return null; }
+ obj.getPeerCertificateFingerprint = function () { if (obj.xtls == 1) { return obj.socket.getPeerCertificate().fingerprint.split(':').join('').toLowerCase(); } return null; }
+
+ // NODE.js specific private method
+ obj.xxOnSocketConnected = function () {
+ if (obj.socket == null) return;
+ if (obj.xtls == 1) {
+ obj.xtlsCertificate = obj.socket.getPeerCertificate();
+
+ // ###BEGIN###{Certificates}
+ // Setup the forge certificate check
+ var camatch = 0;
+ if (obj.xtlsoptions.ca) {
+ var forgeCert = forge.pki.certificateFromAsn1(forge.asn1.fromDer(atob(obj.xtlsCertificate.raw.toString('base64'))));
+ var caStore = forge.pki.createCaStore(obj.xtlsoptions.ca);
+ // Got thru all certificates in the store and look for a match.
+ for (var i in caStore.certs) {
+ if (camatch == 0) {
+ var c = caStore.certs[i], verified = false;
+ try { verified = c.verify(forgeCert); } catch (e) { }
+ if (verified == true) { camatch = c; }
+ }
+ }
+ // We found a match, check that the CommonName matches the hostname
+ if ((obj.xtlsSkipHostCheck == 0) && (camatch != 0)) {
+ amtcertname = forgeCert.subject.getField('CN').value;
+ if (amtcertname.toLowerCase() != obj.host.toLowerCase()) { camatch = 0; }
+ }
+ }
+ if ((camatch == 0) && (obj.xtlsFingerprint != 0) && (obj.xtlsCertificate.fingerprint.split(':').join('').toLowerCase() != obj.xtlsFingerprint)) {
+ obj.FailAllError = 998; // Cause all new responses to be silent. 998 = TLS Certificate check error
+ obj.CancelAllQueries(998);
+ return;
+ }
+ if ((obj.xtlsFingerprint == 0) && (camatch == 0)) { obj.xtlsCheck = 3; } else { obj.xtlsCheck = (camatch == 0) ? 2 : 1; }
+ // ###END###{Certificates}
+ // ###BEGIN###{!Certificates}
+ if ((obj.xtlsFingerprint != 0) && (obj.xtlsCertificate.fingerprint.split(':').join('').toLowerCase() != obj.xtlsFingerprint)) {
+ obj.FailAllError = 998; // Cause all new responses to be silent. 998 = TLS Certificate check error
+ obj.CancelAllQueries(998);
+ return;
+ }
+ obj.xtlsCheck = 2;
+ // ###END###{!Certificates}
+ } else { obj.xtlsCheck = 0; }
+ obj.socketState = 2;
+ obj.socketParseState = 0;
+ for (i in obj.pendingAjaxCall) { obj.sendRequest(obj.pendingAjaxCall[i][0], obj.pendingAjaxCall[i][3], obj.pendingAjaxCall[i][4]); }
+ }
+
+ // NODE.js specific private method
+ obj.xxOnSocketData = function (data) {
+ obj.xtlsDataReceived = true;
+ if (urlvars && urlvars['wsmantrace']) { console.log("WSMAN-RECV(" + data.length + "): " + data); }
+ if (typeof data === 'object') {
+ // This is an ArrayBuffer, convert it to a string array (used in IE)
+ var binary = "", bytes = new Uint8Array(data), length = bytes.byteLength;
+ for (var i = 0; i < length; i++) { binary += String.fromCharCode(bytes[i]); }
+ data = binary;
+ }
+ else if (typeof data !== 'string') return;
+
+ obj.socketAccumulator += data;
+ while (true) {
+ //console.log('ACC(' + obj.socketAccumulator + '): ' + obj.socketAccumulator);
+ if (obj.socketParseState == 0) {
+ var headersize = obj.socketAccumulator.indexOf('\r\n\r\n');
+ if (headersize < 0) return;
+ //obj.Debug(obj.socketAccumulator.substring(0, headersize)); // Display received HTTP header
+ obj.socketHeader = obj.socketAccumulator.substring(0, headersize).split('\r\n');
+ if (obj.amtVersion == null) { for (var i in obj.socketHeader) { if (obj.socketHeader[i].indexOf('Server: Intel(R) Active Management Technology ') == 0) { obj.amtVersion = obj.socketHeader[i].substring(46); } } }
+ obj.socketAccumulator = obj.socketAccumulator.substring(headersize + 4);
+ obj.socketParseState = 1;
+ obj.socketData = '';
+ obj.socketXHeader = { Directive: obj.socketHeader[0].split(' ') };
+ for (i in obj.socketHeader) {
+ if (i != 0) {
+ var x2 = obj.socketHeader[i].indexOf(':');
+ obj.socketXHeader[obj.socketHeader[i].substring(0, x2).toLowerCase()] = obj.socketHeader[i].substring(x2 + 2);
+ }
+ }
+ }
+ if (obj.socketParseState == 1) {
+ var csize = -1;
+ if ((obj.socketXHeader["connection"] != undefined) && (obj.socketXHeader["connection"].toLowerCase() == 'close') && ((obj.socketXHeader["transfer-encoding"] == undefined) || (obj.socketXHeader["transfer-encoding"].toLowerCase() != 'chunked'))) {
+ // The body ends with a close, in this case, we will only process the header
+ csize = 0;
+ } else if (obj.socketXHeader["content-length"] != undefined) {
+ // The body length is specified by the content-length
+ csize = parseInt(obj.socketXHeader["content-length"]);
+ if (obj.socketAccumulator.length < csize) return;
+ var data = obj.socketAccumulator.substring(0, csize);
+ obj.socketAccumulator = obj.socketAccumulator.substring(csize);
+ obj.socketData = data;
+ csize = 0;
+ } else {
+ // The body is chunked
+ var clen = obj.socketAccumulator.indexOf("\r\n");
+ if (clen < 0) return; // Chunk length not found, exit now and get more data.
+ // Chunk length if found, lets see if we can get the data.
+ csize = parseInt(obj.socketAccumulator.substring(0, clen), 16);
+ if (obj.socketAccumulator.length < clen + 2 + csize + 2) return;
+ // We got a chunk with all of the data, handle the chunck now.
+ var data = obj.socketAccumulator.substring(clen + 2, clen + 2 + csize);
+ obj.socketAccumulator = obj.socketAccumulator.substring(clen + 2 + csize + 2);
+ obj.socketData += data;
+ }
+ if (csize == 0) {
+ //obj.Debug("xxOnSocketData DONE: (" + obj.socketData.length + "): " + obj.socketData);
+ obj.xxProcessHttpResponse(obj.socketXHeader, obj.socketData);
+ obj.socketParseState = 0;
+ obj.socketHeader = null;
+ }
+ }
+ }
+ }
+
+ // NODE.js specific private method
+ obj.xxProcessHttpResponse = function (header, data) {
+ //obj.Debug("xxProcessHttpResponse: " + header.Directive[1]);
+
+ var s = parseInt(header.Directive[1]);
+ if (isNaN(s)) s = 500;
+ if (s == 401 && ++(obj.authcounter) < 3) {
+ obj.challengeParams = obj.parseDigest(header['www-authenticate']); // Set the digest parameters, after this, the socket will close and we will auto-retry
+ if (obj.challengeParams['qop'] != null) {
+ var qopList = obj.challengeParams['qop'].split(',');
+ for (var i in qopList) { qopList[i] = qopList[i].trim(); }
+ if (qopList.indexOf('auth-int') >= 0) { obj.challengeParams['qop'] = 'auth-int'; } else { obj.challengeParams['qop'] = 'auth'; }
+ }
+ obj.socket.end();
+ } else {
+ var r = obj.pendingAjaxCall.shift();
+ if (r == null || r.length < 1) { console.log("pendingAjaxCall error, " + r); return; }
+ //if (s != 200) { obj.Debug("Error, status=" + s + "\r\n\r\nreq=" + r[0] + "\r\n\r\nresp=" + data); } // Debug: Display the request & response if something did not work.
+ obj.authcounter = 0;
+ obj.ActiveAjaxCount--;
+ obj.gotNextMessages(data, 'success', { status: s }, r);
+ obj.PerformNextAjax();
+ }
+ }
+
+ // NODE.js specific private method
+ obj.xxOnSocketClosed = function (data) {
+ //obj.Debug("xxOnSocketClosed");
+ obj.socketState = 0;
+ if (obj.socket != null) { obj.socket.destroy(); obj.socket = null; }
+ if (obj.pendingAjaxCall.length > 0) {
+ var r = obj.pendingAjaxCall.shift();
+ var retry = r[5];
+ setTimeout(function () { obj.PerformAjaxExNodeJS2(r[0], r[1], r[2], r[3], r[4], --retry) }, 500); // Wait half a second and try again
+ }
+ }
+
+ // NODE.js specific private method
+ obj.xxSend = function (x) {
+ if (obj.socketState == 2) {
+ if (urlvars && urlvars['wsmantrace']) { console.log("WSMAN-SEND(" + x.length + "): " + x); }
+ obj.socket.write(new Buffer(x, 'binary'));
+ }
+ }
+
+ // Cancel all pending queries with given status
+ obj.CancelAllQueries = function (s) {
+ obj.FailAllError = s;
+ while (obj.PendingAjax.length > 0) { var x = obj.PendingAjax.shift(); x[1](null, s, x[2]); }
+ if (obj.socket != null) { obj.socket.end(); obj.socket = null; obj.socketState = 0; }
+ }
+
+ // Private method
+ obj.gotNextMessages = function (data, status, request, callArgs) {
+ if (obj.FailAllError == 999) return;
+ if (obj.FailAllError != 0) { try { callArgs[1](null, obj.FailAllError, callArgs[2]); } catch (ex) { console.error(ex); } return; }
+ if (request.status != 200) { try { callArgs[1](null, request.status, callArgs[2]); } catch (ex) { console.error(ex); } return; }
+ try { callArgs[1](data, 200, callArgs[2]); } catch (ex) { console.error(ex); }
+ }
+
+ // Private method
+ obj.gotNextMessagesError = function (request, status, errorThrown, callArgs) {
+ if (obj.FailAllError == 999) return;
+ if (obj.FailAllError != 0) { try { callArgs[1](null, obj.FailAllError, callArgs[2]); } catch (ex) { console.error(ex); } return; }
+ try { callArgs[1](obj, null, { Header: { HttpError: request.status } }, request.status, callArgs[2]); } catch (ex) { console.error(ex); }
+ }
+
+ return obj;
+}
+
diff --git a/amt-wsman-ws-0.2.0.js b/amt-wsman-ws-0.2.0.js
new file mode 100644
index 0000000..da69d05
--- /dev/null
+++ b/amt-wsman-ws-0.2.0.js
@@ -0,0 +1,315 @@
+/**
+* @description WSMAN communication using websocket
+* @author Ylian Saint-Hilaire
+* @version v0.2.0c
+*/
+
+// Construct a WSMAN communication object
+var CreateWsmanComm = function (host, port, user, pass, tls) {
+ var obj = {};
+ obj.PendingAjax = []; // List of pending AJAX calls. When one frees up, another will start.
+ obj.ActiveAjaxCount = 0; // Number of currently active AJAX calls
+ obj.MaxActiveAjaxCount = 1; // Maximum number of activate AJAX calls at the same time.
+ obj.FailAllError = 0; // Set this to non-zero to fail all AJAX calls with that error status, 999 causes responses to be silent.
+ obj.challengeParams = null;
+ obj.noncecounter = 1;
+ obj.authcounter = 0;
+ obj.socket = null;
+ obj.socketState = 0;
+ obj.host = host;
+ obj.port = port;
+ obj.user = user;
+ obj.pass = pass;
+ obj.tls = tls;
+ obj.tlsv1only = 0;
+ obj.cnonce = Math.random().toString(36).substring(7); // Generate a random client nonce
+ obj.inDataCount = 0;
+ obj.amtVersion = null;
+ obj.digestRealmMatch = null;
+ obj.digestRealm = null;
+
+ // Private method
+ //obj.Debug = function (msg) { console.log(msg); }
+
+ // Private method
+ // pri = priority, if set to 1, the call is high priority and put on top of the stack.
+ obj.PerformAjax = function (postdata, callback, tag, pri, url, action) {
+ if (obj.ActiveAjaxCount < obj.MaxActiveAjaxCount && obj.PendingAjax.length == 0) {
+ // There are no pending AJAX calls, perform the call now.
+ obj.PerformAjaxEx(postdata, callback, tag, url, action);
+ } else {
+ // If this is a high priority call, put this call in front of the array, otherwise put it in the back.
+ if (pri == 1) { obj.PendingAjax.unshift([postdata, callback, tag, url, action]); } else { obj.PendingAjax.push([postdata, callback, tag, url, action]); }
+ }
+ }
+
+ // Private method
+ obj.PerformNextAjax = function () {
+ if (obj.ActiveAjaxCount >= obj.MaxActiveAjaxCount || obj.PendingAjax.length == 0) return;
+ var x = obj.PendingAjax.shift();
+ obj.PerformAjaxEx(x[0], x[1], x[2], x[3], x[4]);
+ obj.PerformNextAjax();
+ }
+
+ // Private method
+ obj.PerformAjaxEx = function (postdata, callback, tag, url, action) {
+ if (obj.FailAllError != 0) { obj.gotNextMessagesError({ status: obj.FailAllError }, 'error', null, [postdata, callback, tag, url, action]); return; }
+ if (!postdata) postdata = "";
+ //console.log("SEND: " + postdata); // DEBUG
+
+ // We are in a websocket relay environment
+ obj.ActiveAjaxCount++;
+ return obj.PerformAjaxExNodeJS(postdata, callback, tag, url, action);
+ }
+
+ // Websocket relay specific private method
+ obj.pendingAjaxCall = [];
+
+ // Websocket relay specific private method
+ obj.PerformAjaxExNodeJS = function (postdata, callback, tag, url, action) { obj.PerformAjaxExNodeJS2(postdata, callback, tag, url, action, 5); }
+
+ // Websocket relay specific private method
+ obj.PerformAjaxExNodeJS2 = function (postdata, callback, tag, url, action, retry) {
+ //console.log('PerformAjaxExNodeJS2', postdata, retry);
+ if (retry <= 0 || obj.FailAllError != 0) {
+ // Too many retry, fail here.
+ obj.ActiveAjaxCount--;
+ if (obj.FailAllError != 999) obj.gotNextMessages(null, 'error', { status: ((obj.FailAllError == 0) ? 408 : obj.FailAllError) }, [postdata, callback, tag, url, action]); // 408 is timeout error
+ obj.PerformNextAjax();
+ return;
+ }
+ obj.pendingAjaxCall.push([postdata, callback, tag, url, action, retry]);
+ if (obj.socketState == 0) { obj.xxConnectHttpSocket(); }
+ else if (obj.socketState == 2) { obj.sendRequest(postdata, url, action); }
+ }
+
+ // Websocket relay specific private method (Content Length Encoding)
+ obj.sendRequest = function (postdata, url, action) {
+ url = url ? url : "/wsman";
+ action = action ? action : "POST";
+ var h = action + " " + url + " HTTP/1.1\r\n";
+ if (obj.challengeParams != null) {
+ obj.digestRealm = obj.challengeParams["realm"];
+ if (obj.digestRealmMatch && (obj.digestRealm != obj.digestRealmMatch)) {
+ obj.FailAllError = 997; // Cause all new responses to be silent. 997 = Digest Realm check error
+ obj.CancelAllQueries(997);
+ return;
+ }
+ var response = hex_md5(hex_md5(obj.user + ':' + obj.challengeParams['realm'] + ':' + obj.pass) + ':' + obj.challengeParams['nonce'] + ':' + obj.noncecounter + ':' + obj.cnonce + ':' + obj.challengeParams['qop'] + ':' + hex_md5(action + ':' + url + ((obj.challengeParams['qop'] == 'auth-int') ? (':' + hex_md5(postdata)) : '')));
+ h += 'Authorization: ' + obj.renderDigest({ 'username': obj.user, 'realm': obj.challengeParams['realm'], 'nonce': obj.challengeParams['nonce'], 'uri': url, 'qop': obj.challengeParams['qop'], 'response': response, 'nc': obj.noncecounter++, 'cnonce': obj.cnonce }) + '\r\n';
+ }
+ h += 'Host: ' + obj.host + ':' + obj.port + '\r\nContent-Length: ' + postdata.length + '\r\n\r\n' + postdata; // Use Content-Length
+ //h += 'Host: ' + obj.host + ':' + obj.port + '\r\nTransfer-Encoding: chunked\r\n\r\n' + postdata.length.toString(16).toUpperCase() + '\r\n' + postdata + '\r\n0\r\n\r\n'; // Use Chunked-Encoding
+ _Send(h);
+ }
+
+ // Parse the HTTP digest header and return a list of key & values.
+ obj.parseDigest = function (header) { return correctedQuoteSplit(header.substring(7)).reduce(function (obj, s) { var parts = s.trim().split('='); obj[parts[0]] = parts[1].replace(new RegExp('\"', 'g'), ''); return obj; }, {}) }
+
+ // Split a string on quotes but do not do it when in quotes
+ function correctedQuoteSplit(str) { return str.split(',').reduce(function (a, c) { if (a.ic) { a.st[a.st.length - 1] += ',' + c } else { a.st.push(c) } if (c.split('"').length % 2 == 0) { a.ic = !a.ic } return a; }, { st: [], ic: false }).st }
+
+ // Websocket relay specific private method
+ obj.renderDigest = function (params) {
+ var paramsnames = [];
+ for (i in params) { paramsnames.push(i); }
+ return 'Digest ' + paramsnames.reduce(function (s1, ii) { return s1 + ',' + ii + '="' + params[ii] + '"' }, '').substring(1);
+ }
+
+ // Websocket relay specific private method
+ obj.xxConnectHttpSocket = function () {
+ //obj.Debug("xxConnectHttpSocket");
+ obj.inDataCount = 0;
+ obj.socketState = 1;
+ obj.socket = new WebSocket(window.location.protocol.replace("http", "ws") + "//" + window.location.host + window.location.pathname.substring(0, window.location.pathname.lastIndexOf('/')) + "/webrelay.ashx?p=1&host=" + obj.host + "&port=" + obj.port + "&tls=" + obj.tls + "&tls1only=" + obj.tlsv1only + ((user == '*') ? "&serverauth=1" : "") + ((typeof pass === "undefined") ? ("&serverauth=1&user=" + user) : "")); // The "p=1" indicates to the relay that this is a WSMAN session
+ obj.socket.onopen = _OnSocketConnected;
+ obj.socket.onmessage = _OnMessage;
+ obj.socket.onclose = _OnSocketClosed;
+ }
+
+ // Websocket relay specific private method
+ function _OnSocketConnected() {
+ obj.socketState = 2;
+ obj.socketParseState = 0;
+ obj.socketAccumulator = '';
+ obj.socketHeader = null;
+ obj.socketData = '';
+ //console.log("xxOnSocketConnected");
+ for (i in obj.pendingAjaxCall) { obj.sendRequest(obj.pendingAjaxCall[i][0], obj.pendingAjaxCall[i][3], obj.pendingAjaxCall[i][4]); }
+ }
+
+ // Setup the file reader
+ var fileReader = new FileReader();
+ var fileReaderInuse = false, fileReaderAcc = [];
+ if (fileReader.readAsBinaryString) {
+ // Chrome & Firefox (Draft)
+ fileReader.onload = function (e) { _OnSocketData(e.target.result); if (fileReaderAcc.length == 0) { fileReaderInuse = false; } else { fileReader.readAsBinaryString(new Blob([fileReaderAcc.shift()])); } }
+ } else if (fileReader.readAsArrayBuffer) {
+ // Chrome & Firefox (Spec)
+ fileReader.onloadend = function (e) { _OnSocketData(e.target.result); if (fileReaderAcc.length == 0) { fileReaderInuse = false; } else { fileReader.readAsArrayBuffer(fileReaderAcc.shift()); } }
+ }
+
+ function _OnMessage(e) {
+ if (typeof e.data == 'object') {
+ if (fileReaderInuse == true) { fileReaderAcc.push(e.data); return; }
+ if (fileReader.readAsBinaryString) {
+ // Chrome & Firefox (Draft)
+ fileReaderInuse = true;
+ fileReader.readAsBinaryString(new Blob([e.data]));
+ } else if (fileReader.readAsArrayBuffer) {
+ // Chrome & Firefox (Spec)
+ fileReaderInuse = true;
+ fileReader.readAsArrayBuffer(e.data);
+ } else {
+ // IE10, readAsBinaryString does not exist, use an alternative.
+ var binary = "", bytes = new Uint8Array(e.data), length = bytes.byteLength;
+ for (var i = 0; i < length; i++) { binary += String.fromCharCode(bytes[i]); }
+ _OnSocketData(binary);
+ }
+ } else {
+ _OnSocketData(e.data);
+ }
+ };
+
+ // Websocket relay specific private method
+ function _OnSocketData(data) {
+ //obj.Debug("_OnSocketData (" + data.length + "): " + data);
+
+ if (typeof data === 'object') {
+ // This is an ArrayBuffer, convert it to a string array (used in IE)
+ var binary = "", bytes = new Uint8Array(data), length = bytes.byteLength;
+ for (var i = 0; i < length; i++) { binary += String.fromCharCode(bytes[i]); }
+ data = binary;
+ }
+ else if (typeof data !== 'string') return;
+
+ //console.log("RECV(" + obj.socketParseState + "): " + data); // DEBUG
+
+ obj.socketAccumulator += data;
+ while (true) {
+ if (obj.socketParseState == 0) {
+ var headersize = obj.socketAccumulator.indexOf("\r\n\r\n");
+ if (headersize < 0) return;
+ //obj.Debug(obj.socketAccumulator.substring(0, headersize)); // Display received HTTP header
+ obj.socketHeader = obj.socketAccumulator.substring(0, headersize).split("\r\n");
+ if (obj.amtVersion == null) { for (var i in obj.socketHeader) { if (obj.socketHeader[i].indexOf('Server: Intel(R) Active Management Technology ') == 0) { obj.amtVersion = obj.socketHeader[i].substring(46); } } }
+ obj.socketAccumulator = obj.socketAccumulator.substring(headersize + 4);
+ obj.socketParseState = 1;
+ obj.socketData = '';
+ obj.socketXHeader = { Directive: obj.socketHeader[0].split(' ') };
+ //console.log("Header", obj.socketXHeader);
+ for (i in obj.socketHeader) {
+ if (i != 0) {
+ var x2 = obj.socketHeader[i].indexOf(':');
+ obj.socketXHeader[obj.socketHeader[i].substring(0, x2).toLowerCase()] = obj.socketHeader[i].substring(x2 + 2);
+ }
+ }
+ }
+ if (obj.socketParseState == 1) {
+ var csize = -1;
+ if ((obj.socketXHeader['connection'] != undefined) && (obj.socketXHeader['connection'].toLowerCase() == 'close') && ((obj.socketXHeader["transfer-encoding"] == undefined) || (obj.socketXHeader["transfer-encoding"].toLowerCase() != 'chunked'))) {
+ // The body ends with a close, in this case, we will only process the header
+ csize = 0;
+ } else if (obj.socketXHeader['content-length'] != undefined) {
+ // The body length is specified by the content-length
+ csize = parseInt(obj.socketXHeader['content-length']);
+ if (obj.socketAccumulator.length < csize) return;
+ var data = obj.socketAccumulator.substring(0, csize);
+ obj.socketAccumulator = obj.socketAccumulator.substring(csize);
+ obj.socketData = data;
+ csize = 0;
+ } else {
+ // The body is chunked
+ var clen = obj.socketAccumulator.indexOf('\r\n');
+ if (clen < 0) return; // Chunk length not found, exit now and get more data.
+ // Chunk length if found, lets see if we can get the data.
+ csize = parseInt(obj.socketAccumulator.substring(0, clen), 16);
+ if (isNaN(csize)) { if (obj.websocket) { obj.websocket.close(); } return; } // Critical error, close the socket and exit.
+ if (obj.socketAccumulator.length < clen + 2 + csize + 2) return;
+ // We got a chunk with all of the data, handle the chunck now.
+ var data = obj.socketAccumulator.substring(clen + 2, clen + 2 + csize);
+ obj.socketAccumulator = obj.socketAccumulator.substring(clen + 2 + csize + 2);
+ obj.socketData += data;
+ }
+ if (csize == 0) {
+ //obj.Debug("_OnSocketData DONE: (" + obj.socketData.length + "): " + obj.socketData);
+ _ProcessHttpResponse(obj.socketXHeader, obj.socketData);
+ obj.socketParseState = 0;
+ obj.socketHeader = null;
+ }
+ }
+ }
+ }
+
+ // Websocket relay specific private method
+ function _ProcessHttpResponse(header, data) {
+ //obj.Debug("_ProcessHttpResponse: " + header.Directive[1]);
+
+ var s = parseInt(header.Directive[1]);
+ if (isNaN(s)) {
+ s = 602;
+ }
+ if (s == 401 && ++(obj.authcounter) < 3) {
+ obj.challengeParams = obj.parseDigest(header['www-authenticate']); // Set the digest parameters, after this, the socket will close and we will auto-retry
+ if (obj.challengeParams['qop'] != null) {
+ var qopList = obj.challengeParams['qop'].split(',');
+ for (var i in qopList) { qopList[i] = qopList[i].trim(); }
+ if (qopList.indexOf('auth-int') >= 0) { obj.challengeParams['qop'] = 'auth-int'; } else { obj.challengeParams['qop'] = 'auth'; }
+ }
+ } else {
+ var r = obj.pendingAjaxCall.shift();
+ // if (s != 200) { obj.Debug("Error, status=" + s + "\r\n\r\nreq=" + r[0] + "\r\n\r\nresp=" + data); } // Debug: Display the request & response if something did not work.
+ obj.authcounter = 0;
+ obj.ActiveAjaxCount--;
+ obj.gotNextMessages(data, 'success', { status: s }, r);
+ obj.PerformNextAjax();
+ }
+ }
+
+ // Websocket relay specific private method
+ function _OnSocketClosed(data) {
+ //console.log("_OnSocketClosed");
+ if (obj.inDataCount == 0) { obj.tlsv1only = (1 - obj.tlsv1only); }
+ obj.socketState = 0;
+ if (obj.socket != null) { obj.socket.close(); obj.socket = null; }
+ if (obj.pendingAjaxCall.length > 0) {
+ var r = obj.pendingAjaxCall.shift();
+ var retry = r[5];
+ obj.PerformAjaxExNodeJS2(r[0], r[1], r[2], r[3], r[4], --retry);
+ }
+ }
+
+ // Websocket relay specific private method
+ function _Send(x) {
+ //console.log("SEND: " + x); // DEBUG
+ if (obj.socketState == 2 && obj.socket != null && obj.socket.readyState == WebSocket.OPEN) {
+ var b = new Uint8Array(x.length);
+ for (var i = 0; i < x.length; ++i) { b[i] = x.charCodeAt(i); }
+ try { obj.socket.send(b.buffer); } catch (e) { }
+ }
+ }
+
+ // Private method
+ obj.gotNextMessages = function (data, status, request, callArgs) {
+ if (obj.FailAllError == 999) return;
+ if (obj.FailAllError != 0) { callArgs[1](null, obj.FailAllError, callArgs[2]); return; }
+ if (request.status != 200) { callArgs[1](null, request.status, callArgs[2]); return; }
+ callArgs[1](data, 200, callArgs[2]);
+ }
+
+ // Private method
+ obj.gotNextMessagesError = function (request, status, errorThrown, callArgs) {
+ if (obj.FailAllError == 999) return;
+ if (obj.FailAllError != 0) { callArgs[1](null, obj.FailAllError, callArgs[2]); return; }
+ callArgs[1](obj, null, { Header: { HttpError: request.status } }, request.status, callArgs[2]);
+ }
+
+ // Cancel all pending queries with given status
+ obj.CancelAllQueries = function (s) {
+ while (obj.PendingAjax.length > 0) { var x = obj.PendingAjax.shift(); x[1](null, s, x[2]); }
+ if (obj.websocket != null) { obj.websocket.close(); obj.websocket = null; obj.socketState = 0; }
+ }
+
+ return obj;
+}
+
diff --git a/certificate.png b/certificate.png
new file mode 100644
index 0000000000000000000000000000000000000000..3de9ee53dae43675a39240baebf76d00d350a23a
GIT binary patch
literal 529
zcmV+s0`C2ZP)71Q{00001b5ch_0Itp)
z=>Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D02p*dSaefwW^{L9
za%BK;VQFr3E^cLXAT%y8E;(#7eog=Y0fI?HK~zXf#nrznMPUHO@k4%eO9ojK5;B==
z%7np2nZ$5MlSs)VWwaSBO35f28LY}5V336vj24RUecpTC+uL#8lkWQ-p89m|d+vSD
zbMAZ3xhMIL^kD)e=;w*xTm_{n|mAF^xOCV+uCGg>BF`(0pAWPk2ek
zvIaN7g~|yue+&EAbN0=_O}#M2^RNP&Rpfm}%=1uB;YOeMx({`rF05k`w(uD4XX{V=
zkl5wBPq*@zZnH}oCALskrT$lUq1&Of!b5Dr-rS1*;B_LiW)wNC={7Gp?
+ */
+
+/**
+ BEGIN_NODE_INCLUDE
+ var crypto = require('crypto');
+ END_NODE_INCLUDE
+ */
+
+/**
+ * @type {Object.}
+ */
+var crypto = {};
+
+/**
+ * @type {string}
+ */
+crypto.DEFAULT_ENCODING;
+
+/**
+ * @typedef {{pfx: (string|buffer.Buffer), key: (string|buffer.Buffer), passphrase: string, cert: (string|buffer.Buffer), ca: Array., crl: (string|Array.), ciphers: string}}
+ */
+crypto.Credentials;
+
+/**
+ * @param {Object.=} details
+ * @return {crypto.Credentials}
+ */
+crypto.createCredentials =
+function(details) {};
+
+/**
+ * @param {string} algorithm
+ * @return {crypto.Hash}
+ */
+crypto.createHash =
+function(algorithm) {};
+
+/**
+ * @param {string} algorithm
+ * @param {Object=} options
+ * @constructor
+ * @extends stream.Transform
+ */
+crypto.Hash =
+function(algorithm, options) {};
+
+/**
+ * @param {string|buffer.Buffer} data
+ * @param {string=} input_encoding
+ */
+crypto.Hash.prototype.update =
+function(data, input_encoding) {};
+
+/**
+ * @param {string=} encoding
+ * @return {string}
+ */
+crypto.Hash.prototype.digest =
+function(encoding) {};
+
+/**
+ * @param {string} algorithm
+ * @param {string|buffer.Buffer} key
+ * @return {crypto.Hmac}
+ */
+crypto.createHmac =
+function(algorithm, key) {};
+
+/**
+ * @param {string} hmac
+ * @param {string|buffer.Buffer} key
+ * @param {Object=} options
+ * @constructor
+ * @extends stream.Transform
+ */
+crypto.Hmac =
+function(hmac, key, options) {};
+
+/**
+ * @param {string|buffer.Buffer} data
+ */
+crypto.Hmac.prototype.update =
+function(data) {};
+
+/**
+ * @param {string} encoding
+ */
+crypto.Hmac.prototype.digest =
+function(encoding) {};
+
+/**
+ * @param {string} algorithm
+ * @param {string|buffer.Buffer} password
+ * @return {crypto.Cipher}
+ */
+crypto.createCipher =
+function(algorithm, password) {};
+
+/**
+ * @param {string} algorithm
+ * @param {string|buffer.Buffer} key
+ * @param {string|buffer.Buffer} iv
+ * @return {crypto.Cipheriv}
+ */
+crypto.createCipheriv =
+function(algorithm, key, iv) {};
+
+/**
+ * @param {string|buffer.Buffer} cipher
+ * @param {string} password
+ * @param {Object=} options
+ * @constructor
+ * @extends stream.Transform
+ */
+crypto.Cipher =
+function(cipher, password, options) {};
+
+/**
+ * @param {string|buffer.Buffer} data
+ * @param {string=} input_encoding
+ * @param {string=} output_encoding
+ * @return {string|buffer.Buffer}
+ */
+crypto.Cipher.prototype.update =
+function(data, input_encoding, output_encoding) {};
+
+/**
+ * @name crypto.Cipher.prototype.final
+ * @param {string} output_encoding
+ * @return {string|buffer.Buffer}
+ */
+crypto.Cipher.prototype['final'] =
+function(output_encoding) {};
+
+/**
+ * @param {boolean=} auto_padding
+ */
+crypto.Cipher.prototype.setAutoPadding =
+function(auto_padding) {};
+
+/**
+ * Note: Cipheriv mixes update, final, and setAutoPadding from Cipher but
+ * doesn't inherit directly from Cipher.
+ *
+ * @param {string} cipher
+ * @param {string|buffer.Buffer} key
+ * @param {string|buffer.Buffer} iv
+ * @constructor
+ * @extends stream.Transform
+ */
+crypto.Cipheriv =
+function(cipher, key, iv) {};
+
+/**
+ * @param {string|buffer.Buffer} data
+ * @param {string=} input_encoding
+ * @param {string=} output_encoding
+ * @return {string|buffer.Buffer}
+ */
+crypto.Cipheriv.prototype.update =
+function(data, input_encoding, output_encoding) {};
+
+/**
+ * @name crypto.Cipheriv.prototype.final
+ * @param {string} output_encoding
+ * @return {string|buffer.Buffer}
+ */
+crypto.Cipheriv.prototype['final'] =
+function(output_encoding) {};
+
+/**
+ * @param {boolean=} auto_padding
+ */
+crypto.Cipheriv.prototype.setAutoPadding =
+function(auto_padding) {};
+
+/**
+ * @param {string} algorithm
+ * @param {string|buffer.Buffer} password
+ * @return {crypto.Decipher}
+ */
+crypto.createDecipher =
+function(algorithm, password) {};
+
+/**
+ * @param {string} algorithm
+ * @param {string|buffer.Buffer} key
+ * @param {string|buffer.Buffer} iv
+ * @return {crypto.Decipheriv}
+ */
+crypto.createDecipheriv =
+function(algorithm, key, iv) {};
+
+/**
+ * Note: Decipher mixes update, final, and setAutoPadding from Cipher but
+ * doesn't inherit directly from Cipher.
+ *
+ * @param {string|buffer.Buffer} cipher
+ * @param {string|buffer.Buffer} password
+ * @param {Object=} options
+ * @constructor
+ * @extends stream.Transform
+ */
+crypto.Decipher =
+function(cipher, password, options) {}
+
+/**
+ * @param {string|buffer.Buffer} data
+ * @param {string=} input_encoding
+ * @param {string=} output_encoding
+ * @return {string|buffer.Buffer}
+ */
+crypto.Decipher.prototype.update =
+function(data, input_encoding, output_encoding) {};
+
+/**
+ * @name crypto.Decipher.prototype.final
+ * @param {string} output_encoding
+ * @return {string|buffer.Buffer}
+ */
+crypto.Decipher.prototype['final'] =
+function(output_encoding) {};
+
+/**
+ * @param {string} output_encoding
+ * @return {string|buffer.Buffer}
+ */
+crypto.Decipher.prototype.finaltol =
+function(output_encoding) {};
+
+/**
+ * @param {boolean=} auto_padding
+ */
+crypto.Decipher.prototype.setAutoPadding =
+function(auto_padding) {};
+
+/**
+ * Note: Decipheriv mixes update, final, and setAutoPadding from Cipher but
+ * doesn't inherit directly from Cipher.
+ *
+ * @param {string|buffer.Buffer|crypto.Decipheriv} cipher
+ * @param {string|buffer.Buffer} key
+ * @param {string|buffer.Buffer} iv
+ * @param {Object=} options
+ * @constructor
+ * @extends stream.Transform
+ */
+crypto.Decipheriv =
+function(cipher, key, iv, options) {};
+
+/**
+ * @param {string|buffer.Buffer} data
+ * @param {string=} input_encoding
+ * @param {string=} output_encoding
+ * @return {string|buffer.Buffer}
+ */
+crypto.Decipheriv.prototype.update =
+function(data, input_encoding, output_encoding) {};
+
+/**
+ * @name crypto.Decipheriv.prototype.final
+ * @param {string} output_encoding
+ * @return {string|buffer.Buffer}
+ */
+crypto.Decipheriv.prototype['final'] =
+function(output_encoding) {};
+
+/**
+ * @param {string} output_encoding
+ * @return {string|buffer.Buffer}
+ */
+crypto.Decipheriv.prototype.finaltol =
+function(output_encoding) {};
+
+/**
+ * @param {boolean=} auto_padding
+ */
+crypto.Decipheriv.prototype.setAutoPadding =
+function(auto_padding) {};
+
+/**
+ * @param {string} algorithm
+ * @return {crypto.Sign}
+ */
+crypto.createSign =
+function(algorithm) {};
+
+/**
+ * @param {string} algorithm
+ * @param {Object=} options
+ * @constructor
+ * @extends stream.Writable
+ */
+crypto.Sign =
+function(algorithm, options) {};
+
+/**
+ * @param {string|buffer.Buffer} data
+ */
+crypto.Sign.prototype.update =
+function(data) {};
+
+/**
+ * @param {string} private_key
+ * @param {string=} output_format
+ * @return {string|buffer.Buffer}
+ */
+crypto.Sign.prototype.sign =
+function(private_key, output_format) {};
+
+/**
+ * @param {string} algorithm
+ * @return crypto.Verify
+ */
+crypto.createVerify =
+function(algorithm) {};
+
+/**
+ * @param {string} algorithm
+ * @param {Object=} options
+ * @constructor
+ * @extends stream.Writable
+ */
+crypto.Verify =
+function(algorithm, options) {};
+
+/**
+ * @param {string|buffer.Buffer} data
+ */
+crypto.Verify.prototype.update =
+function(data) {};
+
+/**
+ * @param {string} object
+ * @param {string|buffer.Buffer} signature
+ * @param {string=} signature_format
+ * @return {boolean}
+ */
+crypto.Verify.prototype.verify =
+function(object, signature, signature_format) {};
+
+/**
+ * @param {number} prime
+ * @param {string=} encoding
+ * @return {crypto.DiffieHellman}
+ */
+crypto.createDiffieHellman =
+function(prime, encoding) {};
+
+/**
+ * @param {number} sizeOrKey
+ * @param {string=} encoding
+ * @constructor
+ */
+crypto.DiffieHellman =
+function(sizeOrKey, encoding) {};
+
+/**
+ * @param {string=} encoding
+ * @return {string|buffer.Buffer}
+ */
+crypto.DiffieHellman.prototype.generateKeys =
+function(encoding) {};
+
+/**
+ * @param {string|buffer.Buffer} key
+ * @param {string=} inEnc
+ * @param {string=} outEnc
+ * @return {string|buffer.Buffer}
+ */
+crypto.DiffieHellman.prototype.computeSecret =
+function(key, inEnc, outEnc) {};
+
+/**
+ * @param {string=} encoding
+ * @return {string|buffer.Buffer}
+ */
+crypto.DiffieHellman.prototype.getPrime =
+function(encoding) {};
+
+/**
+ * @param {string=} encoding
+ * @return {string|buffer.Buffer}
+ */
+crypto.DiffieHellman.prototype.getGenerator =
+function(encoding) {};
+
+/**
+ * @param {string=} encoding
+ * @return {string|buffer.Buffer}
+ */
+crypto.DiffieHellman.prototype.getPublicKey =
+function(encoding) {};
+
+/**
+ * @param {string} encoding
+ * @return {string|buffer.Buffer}
+ */
+crypto.DiffieHellman.prototype.getPrivateKey =
+function(encoding) {}
+
+/**
+ * @param {string|buffer.Buffer} key
+ * @param {string=} encoding
+ * @return {crypto.DiffieHellman}
+ */
+crypto.DiffieHellman.prototype.setPublicKey =
+function(key, encoding) {};
+
+/**
+ * @param {string|buffer.Buffer} key
+ * @param {string=} encoding
+ * @return {crypto.DiffieHellman}
+ */
+crypto.DiffieHellman.prototype.setPrivateKey =
+function(key, encoding) {};
+
+/**
+ * Note: DiffieHellmanGroup mixes DiffieHellman but doesn't inherit directly.
+ *
+ * @param {string} name
+ * @constructor
+ */
+crypto.DiffieHellmanGroup =
+function(name) {};
+
+/**
+ * @param {string=} encoding
+ * @return {string|buffer.Buffer}
+ */
+crypto.DiffieHellmanGroup.prototype.generateKeys =
+function(encoding) {};
+
+/**
+ * @param {string|buffer.Buffer} key
+ * @param {string=} inEnc
+ * @param {string=} outEnc
+ * @return {string|buffer.Buffer}
+ */
+crypto.DiffieHellmanGroup.prototype.computeSecret =
+function(key, inEnc, outEnc) {};
+
+/**
+ * @param {string=} encoding
+ * @return {string|buffer.Buffer}
+ */
+crypto.DiffieHellmanGroup.prototype.getPrime =
+function(encoding) {};
+
+/**
+ * @param {string=} encoding
+ * @return {string|buffer.Buffer}
+ */
+crypto.DiffieHellmanGroup.prototype.getGenerator =
+function(encoding) {};
+
+/**
+ * @param {string=} encoding
+ * @return {string|buffer.Buffer}
+ */
+crypto.DiffieHellmanGroup.prototype.getPublicKey =
+function(encoding) {};
+
+/**
+ * @param {string} encoding
+ * @return {string|buffer.Buffer}
+ */
+crypto.DiffieHellmanGroup.prototype.getPrivateKey =
+function(encoding) {}
+
+/**
+ * @param {string|buffer.Buffer} key
+ * @param {string=} encoding
+ * @return {crypto.DiffieHellmanGroup}
+ */
+crypto.DiffieHellmanGroup.prototype.setPublicKey =
+function(key, encoding) {};
+
+/**
+ * @param {string|buffer.Buffer} key
+ * @param {string=} encoding
+ * @return {crypto.DiffieHellmanGroup}
+ */
+crypto.DiffieHellmanGroup.prototype.setPrivateKey =
+function(key, encoding) {};
+
+/**
+ * @param {string} group_name
+ * @return {crypto.DiffieHellmanGroup}
+ */
+crypto.getDiffieHellman =
+function(group_name) {};
+
+/**
+ * @param {string|buffer.Buffer} password
+ * @param {string|buffer.Buffer} salt
+ * @param {number} iterations
+ * @param {number} keylen
+ * @param {
+function(*, string)} callback
+ */
+crypto.pbkdf2 =
+function(password, salt, iterations, keylen, callback) {};
+
+/**
+ * @param {string|buffer.Buffer} password
+ * @param {string|buffer.Buffer} salt
+ * @param {number} iterations
+ * @param {number} keylen
+ */
+crypto.pbkdf2Sync =
+function(password, salt, iterations, keylen) {};
+
+/**
+ * @param {number} size
+ * @param {
+function(Error, buffer.Buffer)=} callback
+ */
+crypto.randomBytes =
+function(size, callback) {};
+
+/**
+ * @param {number} size
+ * @param {
+function(Error, buffer.Buffer)=} callback
+ */
+crypto.pseudoRandomBytes =
+function(size, callback) {};
+
+/**
+ * @param {number} size
+ * @param {
+function(Error, buffer.Buffer)=} callback
+ */
+crypto.rng =
+function(size, callback) {};
+
+/**
+ * @param {number} size
+ * @param {
+function(Error, buffer.Buffer)=} callback
+ */
+crypto.prng =
+function(size, callback) {};
+
+/**
+ * @return {Array.}
+ */
+crypto.getCiphers =
+function() {};
+
+/**
+ * @return {Array.}
+ */
+crypto.getHashes =
+function() {};
diff --git a/closure-externs/net.js b/closure-externs/net.js
new file mode 100644
index 0000000..3bfcce8
--- /dev/null
+++ b/closure-externs/net.js
@@ -0,0 +1,249 @@
+/*
+ * Copyright 2012 The Closure Compiler Authors.
+ *
+ * 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.
+ */
+
+/**
+ * @fileoverview Definitions for node's net module. Depends on the events and buffer modules.
+ * @see http://nodejs.org/api/net.html
+ * @see https://github.com/joyent/node/blob/master/lib/net.js
+ * @externs
+ * @author Daniel Wirtz
+ */
+
+/**
+ BEGIN_NODE_INCLUDE
+ var net = require('net');
+ END_NODE_INCLUDE
+ */
+
+/**
+ * @type {Object.}
+ */
+var net = {};
+
+/**
+ * @typedef {{allowHalfOpen: ?boolean}}
+ */
+net.CreateOptions;
+
+/**
+ * @param {(net.CreateOptions|
+function(...))=} options
+ * @param {
+function(...)=} connectionListener
+ * @return {net.Server}
+ */
+net.createServer =
+function(options, connectionListener) {};
+
+/**
+ * @typedef {{port: ?number, host: ?string, localAddress: ?string, path: ?string, allowHalfOpen: ?boolean}}
+ */
+net.ConnectOptions;
+
+/**
+ * @param {net.ConnectOptions|number|string} arg1
+ * @param {(
+function(...)|string)=} arg2
+ * @param {
+function(...)=} arg3
+ */
+net.connect =
+function(arg1, arg2, arg3) {};
+
+/**
+ * @param {net.ConnectOptions|number|string} arg1
+ * @param {(
+function(...)|string)=} arg2
+ * @param {
+function(...)=} arg3
+ */
+net.createConnection =
+function(arg1, arg2, arg3) {};
+
+/**
+ * @constructor
+ * @extends events.EventEmitter
+ */
+net.Server =
+function() {};
+
+/**
+ *
+ * @param {number|*} port
+ * @param {(string|number|
+function(...))=} host
+ * @param {(number|
+function(...))=} backlog
+ * @param {
+function(...)=} callback
+ */
+net.Server.prototype.listen =
+function(port, host, backlog, callback) {};
+
+/**
+ * @param {
+function(...)=} callback
+ */
+net.Server.prototype.close =
+function(callback) {};
+
+/**
+ * @return {{port: number, family: string, address: string}}
+ */
+net.Server.prototype.address =
+function() {};
+
+/**
+ * @type {number}
+ */
+net.Server.prototype.maxConnectinos;
+
+/**
+ * @type {number}
+ */
+net.Server.prototype.connections;
+
+/**
+ * @constructor
+ * @param {{fd: ?*, type: ?string, allowHalfOpen: ?boolean}=} options
+ * @extends events.EventEmitter
+ */
+net.Socket =
+function(options) {};
+
+/**
+ * @param {number|string|
+function(...)} port
+ * @param {(string|
+function(...))=} host
+ * @param {
+function(...)=} connectListener
+ */
+net.Socket.prototype.connect =
+function(port, host, connectListener) {};
+
+/**
+ * @type {number}
+ */
+net.Socket.prototype.bufferSize;
+
+/**
+ * @param {?string=} encoding
+ */
+net.Socket.prototype.setEncoding =
+function (encoding) { };
+net.Socket.prototype.on =
+function (str, func) { };
+
+/**
+ * @param {string|buffer.Buffer} data
+ * @param {(string|
+function(...))=}encoding
+ * @param {
+function(...)=} callback
+ */
+net.Socket.prototype.write =
+function(data, encoding, callback) {};
+
+/**
+ * @param {(string|buffer.Buffer)=}data
+ * @param {string=} encoding
+ */
+net.Socket.prototype.end =
+function(data, encoding) {};
+
+/**
+ */
+net.Socket.prototype.destroy =
+function() {};
+
+/**
+ */
+net.Socket.prototype.pause =
+function() {};
+
+/**
+ */
+net.Socket.prototype.resume =
+function() {};
+
+/**
+ * @param {number} timeout
+ * @param {
+function(...)=} callback
+ */
+net.Socket.prototype.setTimeout =
+function(timeout, callback) {};
+
+/**
+ * @param {boolean=} noDelay
+ */
+net.Socket.prototype.setNoDelay =
+function(noDelay) {};
+
+/**
+ * @param {(boolean|number)=} enable
+ * @param {number=} initialDelay
+ */
+net.Socket.prototype.setKeepAlive =
+function(enable, initialDelay) {};
+
+/**
+ * @return {string}
+ */
+net.Socket.prototype.address =
+function() {};
+
+/**
+ * @type {?string}
+ */
+net.Socket.prototype.remoteAddress;
+
+/**
+ * @type {?number}
+ */
+net.Socket.prototype.remotePort;
+
+/**
+ * @type {number}
+ */
+net.Socket.prototype.bytesRead;
+
+/**
+ * @type {number}
+ */
+net.Socket.prototype.bytesWritten;
+
+/**
+ * @param {*} input
+ * @return {number}
+ */
+net.isIP =
+function(input) {};
+
+/**
+ * @param {*} input
+ * @return {boolean}
+ */
+net.isIPv4 =
+function(input) {};
+
+/**
+ * @param {*} input
+ * @return {boolean}
+ */
+net.isIPv6 =
+function(input) {};
diff --git a/closure-externs/tls.js b/closure-externs/tls.js
new file mode 100644
index 0000000..9ff4345
--- /dev/null
+++ b/closure-externs/tls.js
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2012 The Closure Compiler Authors.
+ *
+ * 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.
+ */
+
+/**
+ * @fileoverview Definitions for node's tls module. Depends on the stream module.
+ * @see http://nodejs.org/api/tls.html
+ * @see https://github.com/joyent/node/blob/master/lib/tls.js
+ * @externs
+ * @author Daniel Wirtz
+ */
+
+/**
+ BEGIN_NODE_INCLUDE
+ var tls = require('tls');
+ END_NODE_INCLUDE
+ */
+
+/**
+ * @type {Object.}
+ */
+var tls = {};
+
+/**
+ * @typedef {{pfx: (string|buffer.Buffer), key: (string|buffer.Buffer), passphrase: string, cert: (string|buffer.Buffer), ca: Array., crl: (string|Array.), ciphers: string, honorCipherOrder: boolean, requestCert: boolean, rejectUnauthorized: boolean, NPNProtocols: (Array|buffer.Buffer), SNICallback:
+function(string), sessionIdContext: string}}
+ */
+tls.CreateOptions;
+
+/**
+ *
+ * @param {tls.CreateOptions} options
+ * @param {
+function(...)=} secureConnectionListener
+ * @return {tls.Server}
+ */
+tls.createServer =
+function(options, secureConnectionListener) {};
+
+/**
+ * @typedef {{host: string, port: number, socket: *, pfx: (string|buffer.Buffer), key: (string|buffer.Buffer), passphrase: string, cert: (string|buffer.Buffer), ca: Array., rejectUnauthorized: boolean, NPNProtocols: Array., servername: string}}
+ */
+tls.ConnectOptions;
+
+/**
+ *
+ * @param {number|tls.ConnectOptions} port
+ * @param {(string|tls.ConnectOptions|
+function(...))=} host
+ * @param {(tls.ConnectOptions|
+function(...))=} options
+ * @param {
+function(...)=} callback
+ */
+tls.connect =
+function(port, host, options, callback) {};
+
+/**
+ * @param {crypto.Credentials=} credentials
+ * @param {boolean=} isServer
+ * @param {boolean=} requestCert
+ * @param {boolean=} rejectUnauthorized
+ * @return {tls.SecurePair}
+ */
+tls.createSecurePair =
+function(credentials, isServer, requestCert, rejectUnauthorized) {};
+
+/**
+ * @constructor
+ * @extends events.EventEmitter
+ */
+tls.SecurePair =
+function() {};
+
+/**
+ * @constructor
+ * @extends net.Server
+ */
+tls.Server =
+function() {};
+
+/**
+ * @param {string} hostname
+ * @param {string|buffer.Buffer} credentials
+ */
+tls.Server.prototype.addContext =
+function(hostname, credentials) {};
+
+/**
+ * @constructor
+ * @extends stream.Duplex
+ */
+tls.CleartextStream =
+function() {};
+
+/**
+ * @type {boolean}
+ */
+tls.CleartextStream.prototype.authorized;
+
+/**
+ * @type {?string}
+ */
+tls.CleartextStream.prototype.authorizationError;
+
+/**
+ * @return {Object.)>}
+ */
+tls.CleartextStream.prototype.getPeerCertificate =
+function() {};
+
+/**
+ * @return {{name: string, version: string}}
+ */
+tls.CleartextStream.prototype.getCipher =
+function() {};
+
+/**
+ * @return {{port: number, family: string, address: string}}
+ */
+tls.CleartextStream.prototype.address =
+function() {};
+
+/**
+ * @type {string}
+ */
+tls.CleartextStream.prototype.remoteAddress;
+
+/**
+ * @type {number}
+ */
+tls.CleartextStream.prototype.remotePort;
diff --git a/common-0.0.1.js b/common-0.0.1.js
new file mode 100644
index 0000000..b228e3b
--- /dev/null
+++ b/common-0.0.1.js
@@ -0,0 +1,105 @@
+/**
+* @description Set of short commonly used methods for handling HTML elements
+* @author Ylian Saint-Hilaire
+* @version v0.0.1b
+*/
+
+// Add startsWith for IE browser
+if (!String.prototype.startsWith) { String.prototype.startsWith = function (str) { return this.lastIndexOf(str, 0) === 0; }; }
+if (!String.prototype.endsWith) { String.prototype.endsWith = function (str) { return this.indexOf(str, this.length - str.length) !== -1; }; }
+
+// Quick UI functions, a bit of a replacement for jQuery
+//function Q(x) { if (document.getElementById(x) == null) { console.log('Invalid element: ' + x); } return document.getElementById(x); } // "Q"
+function Q(x) { return document.getElementById(x); } // "Q"
+function QS(x) { try { return Q(x).style; } catch (x) { } } // "Q" style
+function QE(x, y) { try { Q(x).disabled = !y; } catch (x) { } } // "Q" enable
+function QV(x, y) { try { QS(x).display = (y ? '' : 'none'); } catch (x) { } } // "Q" visible
+function QA(x, y) { Q(x).innerHTML += y; } // "Q" append
+function QH(x, y) { Q(x).innerHTML = y; } // "Q" html
+
+// Move cursor to end of input box
+function inputBoxFocus(x) { Q(x).focus(); var v = Q(x).value; Q(x).value = ''; Q(x).value = v; }
+
+// Binary encoding and decoding functions
+function ReadShort(v, p) { return (v.charCodeAt(p) << 8) + v.charCodeAt(p + 1); }
+function ReadShortX(v, p) { return (v.charCodeAt(p + 1) << 8) + v.charCodeAt(p); }
+function ReadInt(v, p) { return (v.charCodeAt(p) * 0x1000000) + (v.charCodeAt(p + 1) << 16) + (v.charCodeAt(p + 2) << 8) + v.charCodeAt(p + 3); } // We use "*0x1000000" instead of "<<24" because the shift converts the number to signed int32.
+function ReadSInt(v, p) { return (v.charCodeAt(p) << 24) + (v.charCodeAt(p + 1) << 16) + (v.charCodeAt(p + 2) << 8) + v.charCodeAt(p + 3); }
+function ReadIntX(v, p) { return (v.charCodeAt(p + 3) * 0x1000000) + (v.charCodeAt(p + 2) << 16) + (v.charCodeAt(p + 1) << 8) + v.charCodeAt(p); }
+function ShortToStr(v) { return String.fromCharCode((v >> 8) & 0xFF, v & 0xFF); }
+function ShortToStrX(v) { return String.fromCharCode(v & 0xFF, (v >> 8) & 0xFF); }
+function IntToStr(v) { return String.fromCharCode((v >> 24) & 0xFF, (v >> 16) & 0xFF, (v >> 8) & 0xFF, v & 0xFF); }
+function IntToStrX(v) { return String.fromCharCode(v & 0xFF, (v >> 8) & 0xFF, (v >> 16) & 0xFF, (v >> 24) & 0xFF); }
+function MakeToArray(v) { if (!v || v == null || typeof v == 'object') return v; return [v]; }
+function SplitArray(v) { return v.split(','); }
+function Clone(v) { return JSON.parse(JSON.stringify(v)); }
+function EscapeHtml(x) { if (typeof x == "string") return x.replace(/&/g, '&').replace(/>/g, '>').replace(/' + gap(c) + "Item #" + i + ": " + ObjectToStringEx(x[i], c + 1); } }
+ else if (x instanceof Object) { for (var i in x) { r += '
' + gap(c) + i + " = " + ObjectToStringEx(x[i], c + 1); } }
+ else { r += EscapeHtml(x); }
+ return r;
+}
+
+// Print object for console
+function ObjectToStringEx2(x, c) {
+ var r = "";
+ if (x != 0 && (!x || x == null)) return "(Null)";
+ if (x instanceof Array) { for (var i in x) { r += '\r\n' + gap2(c) + "Item #" + i + ": " + ObjectToStringEx2(x[i], c + 1); } }
+ else if (x instanceof Object) { for (var i in x) { r += '\r\n' + gap2(c) + i + " = " + ObjectToStringEx2(x[i], c + 1); } }
+ else { r += EscapeHtml(x); }
+ return r;
+}
+
+// Create an ident gap
+function gap(c) { var x = ''; for (var i = 0; i < (c * 4) ; i++) { x += ' '; } return x; }
+function gap2(c) { var x = ''; for (var i = 0; i < (c * 4) ; i++) { x += ' '; } return x; }
+
+// Print an object in html
+function ObjectToString(x) { return ObjectToStringEx(x, 0); }
+function ObjectToString2(x) { return ObjectToStringEx2(x, 0); }
+
+// Convert a hex string to a raw string
+function hex2rstr(d) {
+ if (typeof d != "string" || d.length == 0) return '';
+ var r = '', m = ('' + d).match(/../g), t;
+ while (t = m.shift()) r += String.fromCharCode('0x' + t);
+ return r
+}
+
+// Convert decimal to hex
+function char2hex(i) { return (i + 0x100).toString(16).substr(-2).toUpperCase(); }
+
+// Convert a raw string to a hex string
+function rstr2hex(input) {
+ var r = '', i;
+ for (i = 0; i < input.length; i++) { r += char2hex(input.charCodeAt(i)); }
+ return r;
+}
+
+// UTF-8 encoding & decoding functions
+function encode_utf8(s) { return unescape(encodeURIComponent(s)); }
+function decode_utf8(s) { return decodeURIComponent(escape(s)); }
+
+// Convert a string into a blob
+function data2blob(data) {
+ var bytes = new Array(data.length);
+ for (var i = 0; i < data.length; i++) bytes[i] = data.charCodeAt(i);
+ var blob = new Blob([new Uint8Array(bytes)]);
+ return blob;
+}
+
+// Generate random numbers
+function random(max) { return Math.floor(Math.random() * max); }
+
+// Trademarks
+function trademarks(x) { return x.replace(/\(R\)/g, '®').replace(/\(TM\)/g, '™'); }
+
+
diff --git a/desktop.ini b/desktop.ini
new file mode 100644
index 0000000..2465586
--- /dev/null
+++ b/desktop.ini
@@ -0,0 +1,2 @@
+[LocalizedFileNames]
+Changes.txt=@Changes.txt,0
diff --git a/favicon-intel.ico b/favicon-intel.ico
new file mode 100644
index 0000000000000000000000000000000000000000..60c8c85130f3cd414f4e200c9d80ae2360ff453b
GIT binary patch
literal 144613
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