first commit
293
.gitignore
vendored
Normal file
@@ -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
|
||||||
201
LICENSE
Normal file
@@ -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.
|
||||||
38
VSSolution.sln
Normal file
@@ -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
|
||||||
781
agent-desktop-0.0.2.js
Normal file
@@ -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;
|
||||||
|
}
|
||||||
145
agent-redir-rtc-0.1.0.js
Normal file
@@ -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;
|
||||||
|
}
|
||||||
987
amt-0.2.0.js
Normal file
@@ -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, "<Address xmlns=\"http://schemas.xmlsoap.org/ws/2004/08/addressing\">http://schemas.xmlsoap.org/ws/2004/08/addressing</Address><ReferenceParameters xmlns=\"http://schemas.xmlsoap.org/ws/2004/08/addressing\"><ResourceURI xmlns=\"http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd\">http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ComputerSystem</ResourceURI><SelectorSet xmlns=\"http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd\"><Selector Name=\"CreationClassName\">CIM_ComputerSystem</Selector><Selector Name=\"Name\">ManagedSystem</Selector></SelectorSet></ReferenceParameters>", null, null, callback_func);
|
||||||
|
}
|
||||||
|
|
||||||
|
obj.RequestOSPowerStateChange = function (PowerState, callback_func) {
|
||||||
|
obj.IPS_PowerManagementService_RequestOSPowerSavingStateChange(PowerState, "<Address xmlns=\"http://schemas.xmlsoap.org/ws/2004/08/addressing\">http://schemas.xmlsoap.org/ws/2004/08/addressing</Address><ReferenceParameters xmlns=\"http://schemas.xmlsoap.org/ws/2004/08/addressing\"><ResourceURI xmlns=\"http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd\">http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ComputerSystem</ResourceURI><SelectorSet xmlns=\"http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd\"><Selector Name=\"CreationClassName\">CIM_ComputerSystem</Selector><Selector Name=\"Name\">ManagedSystem</Selector></SelectorSet></ReferenceParameters>", null, null, callback_func);
|
||||||
|
}
|
||||||
|
|
||||||
|
obj.SetBootConfigRole = function (Role, callback_func) {
|
||||||
|
obj.CIM_BootService_SetBootConfigRole("<Address xmlns=\"http://schemas.xmlsoap.org/ws/2004/08/addressing\">http://schemas.xmlsoap.org/ws/2004/08/addressing</Address><ReferenceParameters xmlns=\"http://schemas.xmlsoap.org/ws/2004/08/addressing\"><ResourceURI xmlns=\"http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd\">http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_BootConfigSetting</ResourceURI><SelectorSet xmlns=\"http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd\"><Selector Name=\"InstanceID\">Intel(r) AMT: Boot Configuration 0</Selector></SelectorSet></ReferenceParameters>", 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<65> 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'] = '<i>Local</i>';
|
||||||
|
ptr = 5;
|
||||||
|
}
|
||||||
|
if (x['InitiatorType'] == 3) {
|
||||||
|
// KVM Default Port
|
||||||
|
x['Initiator'] = '<i>KVM Default Port</i>';
|
||||||
|
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
|
||||||
|
|
||||||
|
<r:WiFiEndpointSettingsInput xmlns:q="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_WiFiEndpointSettings">
|
||||||
|
<q:ElementName>Wireless-Profile-Admin</q:ElementName>
|
||||||
|
<q:InstanceID>Intel(r) AMT:WiFi Endpoint Settings Wireless-Profile-Admin</q:InstanceID>
|
||||||
|
<q:AuthenticationMethod>6</q:AuthenticationMethod>
|
||||||
|
<q:EncryptionMethod>4</q:EncryptionMethod>
|
||||||
|
<q:Priority>100</q:Priority>
|
||||||
|
<q:PSKPassPhrase>xxxxxxxx</q:PSKPassPhrase>
|
||||||
|
</r:WiFiEndpointSettingsInput>
|
||||||
|
*/
|
||||||
|
function instanceToXml(instanceName, inInstance) {
|
||||||
|
if(inInstance === undefined || inInstance === null) return null;
|
||||||
|
|
||||||
|
var hasNamespace = !!inInstance['__namespace'];
|
||||||
|
var startTag = hasNamespace ? '<q:' : '<';
|
||||||
|
var endTag = hasNamespace ? '</q:' : '</';
|
||||||
|
var namespaceDef = hasNamespace ? (' xmlns:q="' + inInstance['__namespace'] + '"' ): '';
|
||||||
|
var result = '<r:' + instanceName + namespaceDef + '>';
|
||||||
|
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 += '</r:' + instanceName + '>';
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a selector set into XML. Expect no nesting.
|
||||||
|
* {
|
||||||
|
* selectorName : selectorValue,
|
||||||
|
* selectorName : selectorValue,
|
||||||
|
* ... ...
|
||||||
|
* }
|
||||||
|
|
||||||
|
<r:WiFiEndpoint>
|
||||||
|
<a:Address>http://192.168.1.103:16992/wsman</a:Address>
|
||||||
|
<a:ReferenceParameters>
|
||||||
|
<w:ResourceURI>http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_WiFiEndpoint</w:ResourceURI>
|
||||||
|
<w:SelectorSet>
|
||||||
|
<w:Selector Name="Name">WiFi Endpoint 0</w:Selector>
|
||||||
|
</w:SelectorSet>
|
||||||
|
</a:ReferenceParameters>
|
||||||
|
</r:WiFiEndpoint>
|
||||||
|
|
||||||
|
*/
|
||||||
|
function referenceToXml(referenceName, inReference) {
|
||||||
|
if(inReference === undefined || inReference === null ) return null;
|
||||||
|
|
||||||
|
var result = '<r:' + referenceName + '><a:Address>/wsman</a:Address><a:ReferenceParameters><w:ResourceURI>'+ inReference['__resourceUri']+'</w:ResourceURI><w:SelectorSet>';
|
||||||
|
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 += '<w:Selector Name="' + selectorName +'">' + inReference[selectorName].toString() + '</w:Selector>';
|
||||||
|
}
|
||||||
|
|
||||||
|
result += '</w:SelectorSet></a:ReferenceParameters></r:' + referenceName + '>';
|
||||||
|
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;
|
||||||
|
}
|
||||||
181
amt-certificates-0.0.1.js
Normal file
@@ -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;
|
||||||
|
}
|
||||||
923
amt-desktop-0.0.2.js
Normal file
@@ -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<6F>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;
|
||||||
|
}
|
||||||
509
amt-ider-node-0.0.1.js
Normal file
@@ -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': '<br>Select a CDROM and Floppy disk image to start the disk redirection.<br><br><br><div style=height:26px;margin-bottom:6px><select style=float:right;width:300px id=storagesourceoption onchange=onIderSourceChange()><option value=0 selected>ISO & IMG from file</option><option value=1>ISO from drive, IMG from file</option><option value=2>ISO from file, IMG from drive</option><option value=3>ISO & IMG from drive</option></select><div>Source</div></div><div style=height:20px><input type=file id=iderisofile accept=.iso style=float:right;width:300px><select style=float:right;width:300px;display:none id=iderisodrive><option>D:</option><option>E:</option><option>F:</option><option>G:</option><option>H:</option><option>I:</option></select><div>.ISO file</div></div><br><div style=height:20px><input type=file id=iderimgfile accept=.img style=float:right;width:300px><select style=float:right;width:300px;display:none id=iderimgdrive><option>A:</option><option>B:</option></select><div>.IMG file</div></div><br /><div style=height:26px><select style=float:right;width:300px id=storageserveroption><option value=0>On Reset</option><option value=1 selected>Gracefully</option><option value=2>Immediately</option></select><div>Start</div></div>' });
|
||||||
|
} else {
|
||||||
|
obj.m.onDialogPrompt(obj.m, { 'html': '<br>Select a CDROM and Floppy disk image to start the disk redirection.<br><br><br><div style=height:20px><input type=file id=iderisofile accept=.iso style=float:right;width:300px><div>.ISO file</div></div><br><div style=height:20px><input type=file id=iderimgfile accept=.img style=float:right;width:300px><div>.IMG file</div></div><br /><div style=height:26px><select style=float:right;width:300px id=storageserveroption><option value=0>On Reset</option><option value=1 selected>Gracefully</option><option value=2>Immediately</option></select><div>Start</div></div>' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
100
amt-ider-server-ws-0.0.1.js
Normal file
@@ -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;
|
||||||
|
}
|
||||||
692
amt-ider-ws-0.0.1.js
Normal file
@@ -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;
|
||||||
|
}
|
||||||
104
amt-lms-0.0.1.js
Normal file
@@ -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;
|
||||||
|
}
|
||||||
323
amt-redir-node-0.1.0.js
Normal file
@@ -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)); }
|
||||||
335
amt-redir-ws-0.1.0.js
Normal file
@@ -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;
|
||||||
|
}
|
||||||
235
amt-scanner-0.1.0.js
Normal file
@@ -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;
|
||||||
|
}
|
||||||
440
amt-script-0.2.0.js
Normal file
@@ -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;
|
||||||
|
}
|
||||||
273
amt-setupbin-0.1.0.js
Normal file
@@ -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<65> 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<6C>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); } }
|
||||||
813
amt-terminal-0.0.2.js
Normal file
@@ -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 + '<br>');
|
||||||
|
}
|
||||||
|
|
||||||
|
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 += '<span style="color:#' + _TermColors[(newat >> x1) & 0x3F] + ';background-color:#' + _TermColors[(newat >> x2) & 0x3F];
|
||||||
|
if (newat & _VTUNDERLINE) buf += ';text-decoration:underline';
|
||||||
|
buf += ';">';
|
||||||
|
closetag = "</span>" + 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 += '<br>';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scrollBackBuffer.length > 800) { scrollBackBuffer = scrollBackBuffer.slice(scrollBackBuffer.length - 800); }
|
||||||
|
var backbuffer = scrollBackBuffer.join('');
|
||||||
|
obj.DivElement.innerHTML = "<font size='4'><b>" + backbuffer + buf + closetag + "</b></font>";
|
||||||
|
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;
|
||||||
|
}
|
||||||
336
amt-wsman-0.2.0.js
Normal file
@@ -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('<?xml version=\"1.0\" encoding=\"utf-8\"?><Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:a="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:w="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd" xmlns=\"http://www.w3.org/2003/05/soap-envelope\" ' + namespaces + '><Header><a:Action>' + 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 = '<t:IssuedTokens xmlns:t="http://schemas.xmlsoap.org/ws/2005/02/trust" xmlns:se="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><t:RequestSecurityTokenResponse><t:TokenType>http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#UsernameToken</t:TokenType><t:RequestedSecurityToken><se:UsernameToken><se:Username>' + user + '</se:Username><se:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd#PasswordText">' + pass + '</se:Password></se:UsernameToken></t:RequestedSecurityToken></t:RequestSecurityTokenResponse></t:IssuedTokens>'; digest2 = '<w:Auth Profile="http://schemas.dmtf.org/wbem/wsman/1/wsman/secprofile/http/digest"/>'; }
|
||||||
|
if (opaque != null) { opaque = '<a:ReferenceParameters><m:arg>' + opaque + '</m:arg></a:ReferenceParameters>'; }
|
||||||
|
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</a:Action><a:To>" + obj.Address + "</a:To><w:ResourceURI>" + resuri + "</w:ResourceURI><a:MessageID>" + (obj.NextMessageId++) + "</a:MessageID><a:ReplyTo><a:Address>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</a:Address></a:ReplyTo>" + _PutObjToSelectorsXml(selectors) + digest + '</Header><Body><e:Subscribe><e:Delivery Mode="http://schemas.' + delivery + '"><e:NotifyTo><a:Address>' + url + '</a:Address>' + opaque + '</e:NotifyTo>' + digest2 + '</e:Delivery></e:Subscribe>';
|
||||||
|
obj.PerformAjax(data + "</Body></Envelope>", 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</a:Action><a:To>" + obj.Address + "</a:To><w:ResourceURI>" + resuri + "</w:ResourceURI><a:MessageID>" + (obj.NextMessageId++) + "</a:MessageID><a:ReplyTo><a:Address>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</a:Address></a:ReplyTo>" + _PutObjToSelectorsXml(selectors) + '</Header><Body><e:Unsubscribe/>';
|
||||||
|
obj.PerformAjax(data + "</Body></Envelope>", 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</a:Action><a:To>" + obj.Address + "</a:To><w:ResourceURI>" + resuri + "</w:ResourceURI><a:MessageID>" + (obj.NextMessageId++) + "</a:MessageID><a:ReplyTo><a:Address>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</a:Address></a:ReplyTo><w:OperationTimeout>PT60.000S</w:OperationTimeout>" + _PutObjToSelectorsXml(selectors) + '</Header><Body>' + _PutObjToBodyXml(resuri, putobj);
|
||||||
|
obj.PerformAjax(data + "</Body></Envelope>", 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</a:Action><a:To>" + obj.Address + "</a:To><w:ResourceURI>" + resuri + "</w:ResourceURI><a:MessageID>" + (obj.NextMessageId++) + "</a:MessageID><a:ReplyTo><a:Address>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</a:Address></a:ReplyTo><w:OperationTimeout>PT60S</w:OperationTimeout>" + _PutObjToSelectorsXml(selectors) + "</Header><Body><g:" + objname + " xmlns:g=\"" + resuri + "\">";
|
||||||
|
for (var n in putobj) { data += "<g:" + n + ">" + putobj[n] + "</g:" + n + ">" }
|
||||||
|
obj.PerformAjax(data + "</g:" + objname + "></Body></Envelope>", 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</a:Action><a:To>" + obj.Address + "</a:To><w:ResourceURI>" + resuri + "</w:ResourceURI><a:MessageID>" + (obj.NextMessageId++) + "</a:MessageID><a:ReplyTo><a:Address>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</a:Address></a:ReplyTo><w:OperationTimeout>PT60S</w:OperationTimeout>" + _PutObjToSelectorsXml(putobj) + "</Header><Body /></Envelope>";
|
||||||
|
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</a:Action><a:To>" + obj.Address + "</a:To><w:ResourceURI>" + resuri + "</w:ResourceURI><a:MessageID>" + (obj.NextMessageId++) + "</a:MessageID><a:ReplyTo><a:Address>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</a:Address></a:ReplyTo><w:OperationTimeout>PT60S</w:OperationTimeout></Header><Body /></Envelope>", 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 += "<r:" + i + ">" + args[i][x] + "</r:" + i + ">"; } } else { argsxml += "<r:" + i + ">" + args[i] + "</r:" + 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 + "</a:Action><a:To>" + obj.Address + "</a:To><w:ResourceURI>" + resuri + "</w:ResourceURI><a:MessageID>" + (obj.NextMessageId++) + "</a:MessageID><a:ReplyTo><a:Address>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</a:Address></a:ReplyTo><w:OperationTimeout>PT60S</w:OperationTimeout>" + _PutObjToSelectorsXml(selectors) + "</Header><Body><r:" + method + '_INPUT' + " xmlns:r=\"" + resuri + "\">" + argsxml + "</r:" + method + "_INPUT></Body></Envelope>", 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</a:Action><a:To>" + obj.Address + "</a:To><w:ResourceURI>" + resuri + "</w:ResourceURI><a:MessageID>" + (obj.NextMessageId++) + "</a:MessageID><a:ReplyTo><a:Address>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</a:Address></a:ReplyTo><w:OperationTimeout>PT60S</w:OperationTimeout></Header><Body><Enumerate xmlns=\"http://schemas.xmlsoap.org/ws/2004/09/enumeration\" /></Body></Envelope>", 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</a:Action><a:To>" + obj.Address + "</a:To><w:ResourceURI>" + resuri + "</w:ResourceURI><a:MessageID>" + (obj.NextMessageId++) + "</a:MessageID><a:ReplyTo><a:Address>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</a:Address></a:ReplyTo><w:OperationTimeout>PT60S</w:OperationTimeout></Header><Body><Pull xmlns=\"http://schemas.xmlsoap.org/ws/2004/09/enumeration\"><EnumerationContext>" + enumctx + "</EnumerationContext></Pull></Body></Envelope>", callback, tag, pri); // </EnumerationContext>--<MaxElements>999</MaxElements><MaxCharacters>99999</MaxCharacters>--</Pull>
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 = '<r:' + objname + ' xmlns:r="' + resuri + '">';
|
||||||
|
|
||||||
|
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 += '<r:' + prop + '><a:Address>' + putObj[prop].Address + '</a:Address><a:ReferenceParameters><w:ResourceURI>' + putObj[prop]['ReferenceParameters']["ResourceURI"] + '</w:ResourceURI><w:SelectorSet>';
|
||||||
|
var selectorArray = putObj[prop]['ReferenceParameters']['SelectorSet']['Selector'];
|
||||||
|
if (Array.isArray(selectorArray)) {
|
||||||
|
for (var i=0; i< selectorArray.length; i++) {
|
||||||
|
result += '<w:Selector' + _ObjectToXmlAttributes(selectorArray[i]) + '>' + selectorArray[i]['Value'] + '</w:Selector>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
result += '<w:Selector' + _ObjectToXmlAttributes(selectorArray) + '>' + selectorArray['Value'] + '</w:Selector>';
|
||||||
|
}
|
||||||
|
result += '</w:SelectorSet></a:ReferenceParameters></r:' + prop + '>';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (Array.isArray(putObj[prop])) {
|
||||||
|
for (var i = 0; i < putObj[prop].length; i++) {
|
||||||
|
result += '<r:' + prop + '>' + putObj[prop][i].toString() + '</r:' + prop + '>';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result += '<r:' + prop + '>' + putObj[prop].toString() + '</r:' + prop + '>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result += '</r:' + objname + '>';
|
||||||
|
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 "<w:SelectorSet><w:Selector Name=\"InstanceID\">" + selectorSet['InstanceID'] + "</w:Selector></w:SelectorSet>";
|
||||||
|
var result = '<w:SelectorSet>';
|
||||||
|
for(var propName in selectorSet) {
|
||||||
|
if (!selectorSet.hasOwnProperty(propName)) continue;
|
||||||
|
result += '<w:Selector Name="' + propName + '">';
|
||||||
|
if (selectorSet[propName]['ReferenceParameters']) {
|
||||||
|
result += '<a:EndpointReference>';
|
||||||
|
result += '<a:Address>' + selectorSet[propName]['Address'] + '</a:Address><a:ReferenceParameters><w:ResourceURI>' + selectorSet[propName]['ReferenceParameters']['ResourceURI'] + '</w:ResourceURI><w:SelectorSet>';
|
||||||
|
var selectorArray = selectorSet[propName]['ReferenceParameters']['SelectorSet']['Selector'];
|
||||||
|
if (Array.isArray(selectorArray)) {
|
||||||
|
for (var i = 0; i < selectorArray.length; i++) {
|
||||||
|
result += '<w:Selector' + _ObjectToXmlAttributes(selectorArray[i]) + '>' + selectorArray[i]['Value'] + '</w:Selector>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
result += '<w:Selector' + _ObjectToXmlAttributes(selectorArray) + '>' + selectorArray['Value'] + '</w:Selector>';
|
||||||
|
}
|
||||||
|
result += '</w:SelectorSet></a:ReferenceParameters></a:EndpointReference>';
|
||||||
|
} else {
|
||||||
|
result += selectorSet[propName];
|
||||||
|
}
|
||||||
|
result += '</w:Selector>';
|
||||||
|
}
|
||||||
|
result += '</w:SelectorSet>';
|
||||||
|
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;
|
||||||
|
}
|
||||||
95
amt-wsman-ajax-0.2.0.js
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
392
amt-wsman-node-0.2.0.js
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
315
amt-wsman-ws-0.2.0.js
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
BIN
certificate.png
Normal file
|
After Width: | Height: | Size: 529 B |
578
closure-externs/crypto.js
Normal file
@@ -0,0 +1,578 @@
|
|||||||
|
/*
|
||||||
|
* 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 crypto module. Depends on the buffer module.
|
||||||
|
* @see http://nodejs.org/api/crypto.html
|
||||||
|
* @see https://github.com/joyent/node/blob/master/lib/crypto.js
|
||||||
|
* @externs
|
||||||
|
* @author Daniel Wirtz <dcode@dcode.io>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
BEGIN_NODE_INCLUDE
|
||||||
|
var crypto = require('crypto');
|
||||||
|
END_NODE_INCLUDE
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {Object.<string,*>}
|
||||||
|
*/
|
||||||
|
var crypto = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
crypto.DEFAULT_ENCODING;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {{pfx: (string|buffer.Buffer), key: (string|buffer.Buffer), passphrase: string, cert: (string|buffer.Buffer), ca: Array.<string|buffer.Buffer>, crl: (string|Array.<string>), ciphers: string}}
|
||||||
|
*/
|
||||||
|
crypto.Credentials;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Object.<string,string>=} 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.<string>}
|
||||||
|
*/
|
||||||
|
crypto.getCiphers =
|
||||||
|
function() {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {Array.<string>}
|
||||||
|
*/
|
||||||
|
crypto.getHashes =
|
||||||
|
function() {};
|
||||||
249
closure-externs/net.js
Normal file
@@ -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 <dcode@dcode.io>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
BEGIN_NODE_INCLUDE
|
||||||
|
var net = require('net');
|
||||||
|
END_NODE_INCLUDE
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {Object.<string,*>}
|
||||||
|
*/
|
||||||
|
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) {};
|
||||||
144
closure-externs/tls.js
Normal file
@@ -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 <dcode@dcode.io>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
BEGIN_NODE_INCLUDE
|
||||||
|
var tls = require('tls');
|
||||||
|
END_NODE_INCLUDE
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {Object.<string,*>}
|
||||||
|
*/
|
||||||
|
var tls = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {{pfx: (string|buffer.Buffer), key: (string|buffer.Buffer), passphrase: string, cert: (string|buffer.Buffer), ca: Array.<string|buffer.Buffer>, crl: (string|Array.<string>), 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.<string>, rejectUnauthorized: boolean, NPNProtocols: Array.<string|buffer.Buffer>, 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.<string,(string|Object.<string,string>)>}
|
||||||
|
*/
|
||||||
|
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;
|
||||||
105
common-0.0.1.js
Normal file
@@ -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(/</g, '<').replace(/"/g, '"').replace(/'/g, '''); if (typeof x == "boolean") return x; if (typeof x == "number") return x; }
|
||||||
|
|
||||||
|
// Move an element from one position in an array to a new position
|
||||||
|
function ArrayElementMove(arr, from, to) { arr.splice(to, 0, arr.splice(from, 1)[0]); };
|
||||||
|
|
||||||
|
// Print object for HTML
|
||||||
|
function ObjectToStringEx(x, c) {
|
||||||
|
var r = "";
|
||||||
|
if (x != 0 && (!x || x == null)) return "(Null)";
|
||||||
|
if (x instanceof Array) { for (var i in x) { r += '<br />' + gap(c) + "Item #" + i + ": " + ObjectToStringEx(x[i], c + 1); } }
|
||||||
|
else if (x instanceof Object) { for (var i in x) { r += '<br />' + 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, '™'); }
|
||||||
|
|
||||||
|
|
||||||
2
desktop.ini
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
[LocalizedFileNames]
|
||||||
|
Changes.txt=@Changes.txt,0
|
||||||
BIN
favicon-intel.ico
Normal file
|
After Width: | Height: | Size: 141 KiB |
BIN
favicon-intel.png
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
BIN
favicon.ico
Normal file
|
After Width: | Height: | Size: 116 KiB |
BIN
favicon.png
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
270
filesaver.1.1.20151003.js
Normal file
@@ -0,0 +1,270 @@
|
|||||||
|
/* FileSaver.js
|
||||||
|
* A saveAs() FileSaver implementation.
|
||||||
|
* 1.1.20151003
|
||||||
|
*
|
||||||
|
* By Eli Grey, http://eligrey.com
|
||||||
|
* License: MIT
|
||||||
|
* See https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*global self */
|
||||||
|
/*jslint bitwise: true, indent: 4, laxbreak: true, laxcomma: true, smarttabs: true, plusplus: true */
|
||||||
|
|
||||||
|
/*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */
|
||||||
|
|
||||||
|
var saveAs = saveAs || (function (view) {
|
||||||
|
"use strict";
|
||||||
|
// IE <10 is explicitly unsupported
|
||||||
|
if (typeof navigator !== "undefined" && /MSIE [1-9]\./.test(navigator.userAgent)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var
|
||||||
|
doc = view.document
|
||||||
|
// only get URL when necessary in case Blob.js hasn't overridden it yet
|
||||||
|
, get_URL = function () {
|
||||||
|
return view.URL || view.webkitURL || view;
|
||||||
|
}
|
||||||
|
, save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a")
|
||||||
|
, can_use_save_link = "download" in save_link
|
||||||
|
, click = function (node) {
|
||||||
|
var event = new MouseEvent("click");
|
||||||
|
node.dispatchEvent(event);
|
||||||
|
}
|
||||||
|
, is_safari = /Version\/[\d\.]+.*Safari/.test(navigator.userAgent)
|
||||||
|
, webkit_req_fs = view.webkitRequestFileSystem
|
||||||
|
, req_fs = view.requestFileSystem || webkit_req_fs || view.mozRequestFileSystem
|
||||||
|
, throw_outside = function (ex) {
|
||||||
|
(view.setImmediate || view.setTimeout)(function () {
|
||||||
|
throw ex;
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
, force_saveable_type = "application/octet-stream"
|
||||||
|
, fs_min_size = 0
|
||||||
|
// See https://code.google.com/p/chromium/issues/detail?id=375297#c7 and
|
||||||
|
// https://github.com/eligrey/FileSaver.js/commit/485930a#commitcomment-8768047
|
||||||
|
// for the reasoning behind the timeout and revocation flow
|
||||||
|
, arbitrary_revoke_timeout = 500 // in ms
|
||||||
|
, revoke = function (file) {
|
||||||
|
var revoker = function () {
|
||||||
|
if (typeof file === "string") { // file is an object URL
|
||||||
|
get_URL().revokeObjectURL(file);
|
||||||
|
} else { // file is a File
|
||||||
|
file.remove();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (view.chrome) {
|
||||||
|
revoker();
|
||||||
|
} else {
|
||||||
|
setTimeout(revoker, arbitrary_revoke_timeout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
, dispatch = function (filesaver, event_types, event) {
|
||||||
|
event_types = [].concat(event_types);
|
||||||
|
var i = event_types.length;
|
||||||
|
while (i--) {
|
||||||
|
var listener = filesaver["on" + event_types[i]];
|
||||||
|
if (typeof listener === "function") {
|
||||||
|
try {
|
||||||
|
listener.call(filesaver, event || filesaver);
|
||||||
|
} catch (ex) {
|
||||||
|
throw_outside(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
, auto_bom = function (blob) {
|
||||||
|
// prepend BOM for UTF-8 XML and text types (including HTML)
|
||||||
|
if (/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(blob.type)) {
|
||||||
|
return new Blob(["\ufeff", blob], { type: blob.type });
|
||||||
|
}
|
||||||
|
return blob;
|
||||||
|
}
|
||||||
|
, FileSaver = function (blob, name, no_auto_bom) {
|
||||||
|
if (!no_auto_bom) {
|
||||||
|
blob = auto_bom(blob);
|
||||||
|
}
|
||||||
|
// First try a.download, then web filesystem, then object URLs
|
||||||
|
var
|
||||||
|
filesaver = this
|
||||||
|
, type = blob.type
|
||||||
|
, blob_changed = false
|
||||||
|
, object_url
|
||||||
|
, target_view
|
||||||
|
, dispatch_all = function () {
|
||||||
|
dispatch(filesaver, "writestart progress write writeend".split(" "));
|
||||||
|
}
|
||||||
|
// on any filesys errors revert to saving with object URLs
|
||||||
|
, fs_error = function () {
|
||||||
|
if (target_view && is_safari && typeof FileReader !== "undefined") {
|
||||||
|
// Safari doesn't allow downloading of blob urls
|
||||||
|
var reader = new FileReader();
|
||||||
|
reader.onloadend = function () {
|
||||||
|
var base64Data = reader.result;
|
||||||
|
target_view.location.href = "data:attachment/file" + base64Data.slice(base64Data.search(/[,;]/));
|
||||||
|
filesaver.readyState = filesaver.DONE;
|
||||||
|
dispatch_all();
|
||||||
|
};
|
||||||
|
reader.readAsDataURL(blob);
|
||||||
|
filesaver.readyState = filesaver.INIT;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// don't create more object URLs than needed
|
||||||
|
if (blob_changed || !object_url) {
|
||||||
|
object_url = get_URL().createObjectURL(blob);
|
||||||
|
}
|
||||||
|
if (target_view) {
|
||||||
|
target_view.location.href = object_url;
|
||||||
|
} else {
|
||||||
|
var new_tab = view.open(object_url, "_blank");
|
||||||
|
if (new_tab == undefined && is_safari) {
|
||||||
|
//Apple do not allow window.open, see http://bit.ly/1kZffRI
|
||||||
|
view.location.href = object_url
|
||||||
|
}
|
||||||
|
}
|
||||||
|
filesaver.readyState = filesaver.DONE;
|
||||||
|
dispatch_all();
|
||||||
|
revoke(object_url);
|
||||||
|
}
|
||||||
|
, abortable = function (func) {
|
||||||
|
return function () {
|
||||||
|
if (filesaver.readyState !== filesaver.DONE) {
|
||||||
|
return func.apply(this, arguments);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
, create_if_not_found = { create: true, exclusive: false }
|
||||||
|
, slice
|
||||||
|
;
|
||||||
|
filesaver.readyState = filesaver.INIT;
|
||||||
|
if (!name) {
|
||||||
|
name = "download";
|
||||||
|
}
|
||||||
|
if (can_use_save_link) {
|
||||||
|
object_url = get_URL().createObjectURL(blob);
|
||||||
|
save_link.href = object_url;
|
||||||
|
save_link.download = name;
|
||||||
|
setTimeout(function () {
|
||||||
|
click(save_link);
|
||||||
|
dispatch_all();
|
||||||
|
revoke(object_url);
|
||||||
|
filesaver.readyState = filesaver.DONE;
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Object and web filesystem URLs have a problem saving in Google Chrome when
|
||||||
|
// viewed in a tab, so I force save with application/octet-stream
|
||||||
|
// http://code.google.com/p/chromium/issues/detail?id=91158
|
||||||
|
// Update: Google errantly closed 91158, I submitted it again:
|
||||||
|
// https://code.google.com/p/chromium/issues/detail?id=389642
|
||||||
|
if (view.chrome && type && type !== force_saveable_type) {
|
||||||
|
slice = blob.slice || blob.webkitSlice;
|
||||||
|
blob = slice.call(blob, 0, blob.size, force_saveable_type);
|
||||||
|
blob_changed = true;
|
||||||
|
}
|
||||||
|
// Since I can't be sure that the guessed media type will trigger a download
|
||||||
|
// in WebKit, I append .download to the filename.
|
||||||
|
// https://bugs.webkit.org/show_bug.cgi?id=65440
|
||||||
|
if (webkit_req_fs && name !== "download") {
|
||||||
|
name += ".download";
|
||||||
|
}
|
||||||
|
if (type === force_saveable_type || webkit_req_fs) {
|
||||||
|
target_view = view;
|
||||||
|
}
|
||||||
|
if (!req_fs) {
|
||||||
|
fs_error();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fs_min_size += blob.size;
|
||||||
|
req_fs(view.TEMPORARY, fs_min_size, abortable(function (fs) {
|
||||||
|
fs.root.getDirectory("saved", create_if_not_found, abortable(function (dir) {
|
||||||
|
var save = function () {
|
||||||
|
dir.getFile(name, create_if_not_found, abortable(function (file) {
|
||||||
|
file.createWriter(abortable(function (writer) {
|
||||||
|
writer.onwriteend = function (event) {
|
||||||
|
target_view.location.href = file.toURL();
|
||||||
|
filesaver.readyState = filesaver.DONE;
|
||||||
|
dispatch(filesaver, "writeend", event);
|
||||||
|
revoke(file);
|
||||||
|
};
|
||||||
|
writer.onerror = function () {
|
||||||
|
var error = writer.error;
|
||||||
|
if (error.code !== error.ABORT_ERR) {
|
||||||
|
fs_error();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
"writestart progress write abort".split(" ").forEach(function (event) {
|
||||||
|
writer["on" + event] = filesaver["on" + event];
|
||||||
|
});
|
||||||
|
writer.write(blob);
|
||||||
|
filesaver.abort = function () {
|
||||||
|
writer.abort();
|
||||||
|
filesaver.readyState = filesaver.DONE;
|
||||||
|
};
|
||||||
|
filesaver.readyState = filesaver.WRITING;
|
||||||
|
}), fs_error);
|
||||||
|
}), fs_error);
|
||||||
|
};
|
||||||
|
dir.getFile(name, { create: false }, abortable(function (file) {
|
||||||
|
// delete file if it already exists
|
||||||
|
file.remove();
|
||||||
|
save();
|
||||||
|
}), abortable(function (ex) {
|
||||||
|
if (ex.code === ex.NOT_FOUND_ERR) {
|
||||||
|
save();
|
||||||
|
} else {
|
||||||
|
fs_error();
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}), fs_error);
|
||||||
|
}), fs_error);
|
||||||
|
}
|
||||||
|
, FS_proto = FileSaver.prototype
|
||||||
|
, saveAs = function (blob, name, no_auto_bom) {
|
||||||
|
return new FileSaver(blob, name, no_auto_bom);
|
||||||
|
}
|
||||||
|
;
|
||||||
|
// IE 10+ (native saveAs)
|
||||||
|
if (typeof navigator !== "undefined" && navigator.msSaveOrOpenBlob) {
|
||||||
|
return function (blob, name, no_auto_bom) {
|
||||||
|
if (!no_auto_bom) {
|
||||||
|
blob = auto_bom(blob);
|
||||||
|
}
|
||||||
|
return navigator.msSaveOrOpenBlob(blob, name || "download");
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
FS_proto.abort = function () {
|
||||||
|
var filesaver = this;
|
||||||
|
filesaver.readyState = filesaver.DONE;
|
||||||
|
dispatch(filesaver, "abort");
|
||||||
|
};
|
||||||
|
FS_proto.readyState = FS_proto.INIT = 0;
|
||||||
|
FS_proto.WRITING = 1;
|
||||||
|
FS_proto.DONE = 2;
|
||||||
|
|
||||||
|
FS_proto.error =
|
||||||
|
FS_proto.onwritestart =
|
||||||
|
FS_proto.onprogress =
|
||||||
|
FS_proto.onwrite =
|
||||||
|
FS_proto.onabort =
|
||||||
|
FS_proto.onerror =
|
||||||
|
FS_proto.onwriteend =
|
||||||
|
null;
|
||||||
|
|
||||||
|
return saveAs;
|
||||||
|
}(
|
||||||
|
typeof self !== "undefined" && self
|
||||||
|
|| typeof window !== "undefined" && window
|
||||||
|
|| this.content
|
||||||
|
));
|
||||||
|
// `self` is undefined in Firefox for Android content script context
|
||||||
|
// while `this` is nsIContentFrameMessageManager
|
||||||
|
// with an attribute `content` that corresponds to the window
|
||||||
|
|
||||||
|
if (typeof module !== "undefined" && module.exports) {
|
||||||
|
module.exports.saveAs = saveAs;
|
||||||
|
} else if ((typeof define !== "undefined" && define !== null) && (define.amd != null)) {
|
||||||
|
define([], function () {
|
||||||
|
return saveAs;
|
||||||
|
});
|
||||||
|
}
|
||||||
1147
forge.js/aes.js
Normal file
338
forge.js/aesCipherSuites.js
Normal file
@@ -0,0 +1,338 @@
|
|||||||
|
/**
|
||||||
|
* A Javascript implementation of AES Cipher Suites for TLS.
|
||||||
|
*
|
||||||
|
* @author Dave Longley
|
||||||
|
*
|
||||||
|
* Copyright (c) 2009-2015 Digital Bazaar, Inc.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
(function() {
|
||||||
|
/* ########## Begin module implementation ########## */
|
||||||
|
function initModule(forge) {
|
||||||
|
|
||||||
|
var tls = forge.tls;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Supported cipher suites.
|
||||||
|
*/
|
||||||
|
tls.CipherSuites['TLS_RSA_WITH_AES_128_CBC_SHA'] = {
|
||||||
|
id: [0x00,0x2f],
|
||||||
|
name: 'TLS_RSA_WITH_AES_128_CBC_SHA',
|
||||||
|
initSecurityParameters: function(sp) {
|
||||||
|
sp.bulk_cipher_algorithm = tls.BulkCipherAlgorithm.aes;
|
||||||
|
sp.cipher_type = tls.CipherType.block;
|
||||||
|
sp.enc_key_length = 16;
|
||||||
|
sp.block_length = 16;
|
||||||
|
sp.fixed_iv_length = 16;
|
||||||
|
sp.record_iv_length = 16;
|
||||||
|
sp.mac_algorithm = tls.MACAlgorithm.hmac_sha1;
|
||||||
|
sp.mac_length = 20;
|
||||||
|
sp.mac_key_length = 20;
|
||||||
|
},
|
||||||
|
initConnectionState: initConnectionState
|
||||||
|
};
|
||||||
|
tls.CipherSuites['TLS_RSA_WITH_AES_256_CBC_SHA'] = {
|
||||||
|
id: [0x00,0x35],
|
||||||
|
name: 'TLS_RSA_WITH_AES_256_CBC_SHA',
|
||||||
|
initSecurityParameters: function(sp) {
|
||||||
|
sp.bulk_cipher_algorithm = tls.BulkCipherAlgorithm.aes;
|
||||||
|
sp.cipher_type = tls.CipherType.block;
|
||||||
|
sp.enc_key_length = 32;
|
||||||
|
sp.block_length = 16;
|
||||||
|
sp.fixed_iv_length = 16;
|
||||||
|
sp.record_iv_length = 16;
|
||||||
|
sp.mac_algorithm = tls.MACAlgorithm.hmac_sha1;
|
||||||
|
sp.mac_length = 20;
|
||||||
|
sp.mac_key_length = 20;
|
||||||
|
},
|
||||||
|
initConnectionState: initConnectionState
|
||||||
|
};
|
||||||
|
|
||||||
|
function initConnectionState(state, c, sp) {
|
||||||
|
var client = (c.entity === forge.tls.ConnectionEnd.client);
|
||||||
|
|
||||||
|
// cipher setup
|
||||||
|
state.read.cipherState = {
|
||||||
|
init: false,
|
||||||
|
cipher: forge.cipher.createDecipher('AES-CBC', client ?
|
||||||
|
sp.keys.server_write_key : sp.keys.client_write_key),
|
||||||
|
iv: client ? sp.keys.server_write_IV : sp.keys.client_write_IV
|
||||||
|
};
|
||||||
|
state.write.cipherState = {
|
||||||
|
init: false,
|
||||||
|
cipher: forge.cipher.createCipher('AES-CBC', client ?
|
||||||
|
sp.keys.client_write_key : sp.keys.server_write_key),
|
||||||
|
iv: client ? sp.keys.client_write_IV : sp.keys.server_write_IV
|
||||||
|
};
|
||||||
|
state.read.cipherFunction = decrypt_aes_cbc_sha1;
|
||||||
|
state.write.cipherFunction = encrypt_aes_cbc_sha1;
|
||||||
|
|
||||||
|
// MAC setup
|
||||||
|
state.read.macLength = state.write.macLength = sp.mac_length;
|
||||||
|
state.read.macFunction = state.write.macFunction = tls.hmac_sha1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encrypts the TLSCompressed record into a TLSCipherText record using AES
|
||||||
|
* in CBC mode.
|
||||||
|
*
|
||||||
|
* @param record the TLSCompressed record to encrypt.
|
||||||
|
* @param s the ConnectionState to use.
|
||||||
|
*
|
||||||
|
* @return true on success, false on failure.
|
||||||
|
*/
|
||||||
|
function encrypt_aes_cbc_sha1(record, s) {
|
||||||
|
var rval = false;
|
||||||
|
|
||||||
|
// append MAC to fragment, update sequence number
|
||||||
|
var mac = s.macFunction(s.macKey, s.sequenceNumber, record);
|
||||||
|
record.fragment.putBytes(mac);
|
||||||
|
s.updateSequenceNumber();
|
||||||
|
|
||||||
|
// TLS 1.1+ use an explicit IV every time to protect against CBC attacks
|
||||||
|
var iv;
|
||||||
|
if(record.version.minor === tls.Versions.TLS_1_0.minor) {
|
||||||
|
// use the pre-generated IV when initializing for TLS 1.0, otherwise use
|
||||||
|
// the residue from the previous encryption
|
||||||
|
iv = s.cipherState.init ? null : s.cipherState.iv;
|
||||||
|
} else {
|
||||||
|
iv = forge.random.getBytesSync(16);
|
||||||
|
}
|
||||||
|
|
||||||
|
s.cipherState.init = true;
|
||||||
|
|
||||||
|
// start cipher
|
||||||
|
var cipher = s.cipherState.cipher;
|
||||||
|
cipher.start({iv: iv});
|
||||||
|
|
||||||
|
// TLS 1.1+ write IV into output
|
||||||
|
if(record.version.minor >= tls.Versions.TLS_1_1.minor) {
|
||||||
|
cipher.output.putBytes(iv);
|
||||||
|
}
|
||||||
|
|
||||||
|
// do encryption (default padding is appropriate)
|
||||||
|
cipher.update(record.fragment);
|
||||||
|
if(cipher.finish(encrypt_aes_cbc_sha1_padding)) {
|
||||||
|
// set record fragment to encrypted output
|
||||||
|
record.fragment = cipher.output;
|
||||||
|
record.length = record.fragment.length();
|
||||||
|
rval = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles padding for aes_cbc_sha1 in encrypt mode.
|
||||||
|
*
|
||||||
|
* @param blockSize the block size.
|
||||||
|
* @param input the input buffer.
|
||||||
|
* @param decrypt true in decrypt mode, false in encrypt mode.
|
||||||
|
*
|
||||||
|
* @return true on success, false on failure.
|
||||||
|
*/
|
||||||
|
function encrypt_aes_cbc_sha1_padding(blockSize, input, decrypt) {
|
||||||
|
/* The encrypted data length (TLSCiphertext.length) is one more than the sum
|
||||||
|
of SecurityParameters.block_length, TLSCompressed.length,
|
||||||
|
SecurityParameters.mac_length, and padding_length.
|
||||||
|
|
||||||
|
The padding may be any length up to 255 bytes long, as long as it results in
|
||||||
|
the TLSCiphertext.length being an integral multiple of the block length.
|
||||||
|
Lengths longer than necessary might be desirable to frustrate attacks on a
|
||||||
|
protocol based on analysis of the lengths of exchanged messages. Each uint8
|
||||||
|
in the padding data vector must be filled with the padding length value.
|
||||||
|
|
||||||
|
The padding length should be such that the total size of the
|
||||||
|
GenericBlockCipher structure is a multiple of the cipher's block length.
|
||||||
|
Legal values range from zero to 255, inclusive. This length specifies the
|
||||||
|
length of the padding field exclusive of the padding_length field itself.
|
||||||
|
|
||||||
|
This is slightly different from PKCS#7 because the padding value is 1
|
||||||
|
less than the actual number of padding bytes if you include the
|
||||||
|
padding_length uint8 itself as a padding byte. */
|
||||||
|
if(!decrypt) {
|
||||||
|
// get the number of padding bytes required to reach the blockSize and
|
||||||
|
// subtract 1 for the padding value (to make room for the padding_length
|
||||||
|
// uint8)
|
||||||
|
var padding = blockSize - (input.length() % blockSize);
|
||||||
|
input.fillWithByte(padding - 1, padding);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles padding for aes_cbc_sha1 in decrypt mode.
|
||||||
|
*
|
||||||
|
* @param blockSize the block size.
|
||||||
|
* @param output the output buffer.
|
||||||
|
* @param decrypt true in decrypt mode, false in encrypt mode.
|
||||||
|
*
|
||||||
|
* @return true on success, false on failure.
|
||||||
|
*/
|
||||||
|
function decrypt_aes_cbc_sha1_padding(blockSize, output, decrypt) {
|
||||||
|
var rval = true;
|
||||||
|
if(decrypt) {
|
||||||
|
/* The last byte in the output specifies the number of padding bytes not
|
||||||
|
including itself. Each of the padding bytes has the same value as that
|
||||||
|
last byte (known as the padding_length). Here we check all padding
|
||||||
|
bytes to ensure they have the value of padding_length even if one of
|
||||||
|
them is bad in order to ward-off timing attacks. */
|
||||||
|
var len = output.length();
|
||||||
|
var paddingLength = output.last();
|
||||||
|
for(var i = len - 1 - paddingLength; i < len - 1; ++i) {
|
||||||
|
rval = rval && (output.at(i) == paddingLength);
|
||||||
|
}
|
||||||
|
if(rval) {
|
||||||
|
// trim off padding bytes and last padding length byte
|
||||||
|
output.truncate(paddingLength + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decrypts a TLSCipherText record into a TLSCompressed record using
|
||||||
|
* AES in CBC mode.
|
||||||
|
*
|
||||||
|
* @param record the TLSCipherText record to decrypt.
|
||||||
|
* @param s the ConnectionState to use.
|
||||||
|
*
|
||||||
|
* @return true on success, false on failure.
|
||||||
|
*/
|
||||||
|
var count = 0;
|
||||||
|
function decrypt_aes_cbc_sha1(record, s) {
|
||||||
|
var rval = false;
|
||||||
|
++count;
|
||||||
|
|
||||||
|
var iv;
|
||||||
|
if(record.version.minor === tls.Versions.TLS_1_0.minor) {
|
||||||
|
// use pre-generated IV when initializing for TLS 1.0, otherwise use the
|
||||||
|
// residue from the previous decryption
|
||||||
|
iv = s.cipherState.init ? null : s.cipherState.iv;
|
||||||
|
} else {
|
||||||
|
// TLS 1.1+ use an explicit IV every time to protect against CBC attacks
|
||||||
|
// that is appended to the record fragment
|
||||||
|
iv = record.fragment.getBytes(16);
|
||||||
|
}
|
||||||
|
|
||||||
|
s.cipherState.init = true;
|
||||||
|
|
||||||
|
// start cipher
|
||||||
|
var cipher = s.cipherState.cipher;
|
||||||
|
cipher.start({iv: iv});
|
||||||
|
|
||||||
|
// do decryption
|
||||||
|
cipher.update(record.fragment);
|
||||||
|
rval = cipher.finish(decrypt_aes_cbc_sha1_padding);
|
||||||
|
|
||||||
|
// even if decryption fails, keep going to minimize timing attacks
|
||||||
|
|
||||||
|
// decrypted data:
|
||||||
|
// first (len - 20) bytes = application data
|
||||||
|
// last 20 bytes = MAC
|
||||||
|
var macLen = s.macLength;
|
||||||
|
|
||||||
|
// create a random MAC to check against should the mac length check fail
|
||||||
|
// Note: do this regardless of the failure to keep timing consistent
|
||||||
|
var mac = forge.random.getBytesSync(macLen);
|
||||||
|
|
||||||
|
// get fragment and mac
|
||||||
|
var len = cipher.output.length();
|
||||||
|
if(len >= macLen) {
|
||||||
|
record.fragment = cipher.output.getBytes(len - macLen);
|
||||||
|
mac = cipher.output.getBytes(macLen);
|
||||||
|
} else {
|
||||||
|
// bad data, but get bytes anyway to try to keep timing consistent
|
||||||
|
record.fragment = cipher.output.getBytes();
|
||||||
|
}
|
||||||
|
record.fragment = forge.util.createBuffer(record.fragment);
|
||||||
|
record.length = record.fragment.length();
|
||||||
|
|
||||||
|
// see if data integrity checks out, update sequence number
|
||||||
|
var mac2 = s.macFunction(s.macKey, s.sequenceNumber, record);
|
||||||
|
s.updateSequenceNumber();
|
||||||
|
rval = compareMacs(s.macKey, mac, mac2) && rval;
|
||||||
|
return rval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Safely compare two MACs. This function will compare two MACs in a way
|
||||||
|
* that protects against timing attacks.
|
||||||
|
*
|
||||||
|
* TODO: Expose elsewhere as a utility API.
|
||||||
|
*
|
||||||
|
* See: https://www.nccgroup.trust/us/about-us/newsroom-and-events/blog/2011/february/double-hmac-verification/
|
||||||
|
*
|
||||||
|
* @param key the MAC key to use.
|
||||||
|
* @param mac1 as a binary-encoded string of bytes.
|
||||||
|
* @param mac2 as a binary-encoded string of bytes.
|
||||||
|
*
|
||||||
|
* @return true if the MACs are the same, false if not.
|
||||||
|
*/
|
||||||
|
function compareMacs(key, mac1, mac2) {
|
||||||
|
var hmac = forge.hmac.create();
|
||||||
|
|
||||||
|
hmac.start('SHA1', key);
|
||||||
|
hmac.update(mac1);
|
||||||
|
mac1 = hmac.digest().getBytes();
|
||||||
|
|
||||||
|
hmac.start(null, null);
|
||||||
|
hmac.update(mac2);
|
||||||
|
mac2 = hmac.digest().getBytes();
|
||||||
|
|
||||||
|
return mac1 === mac2;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end module implementation
|
||||||
|
|
||||||
|
/* ########## Begin module wrapper ########## */
|
||||||
|
var name = 'aesCipherSuites';
|
||||||
|
if(typeof define !== 'function') {
|
||||||
|
// NodeJS -> AMD
|
||||||
|
if(typeof module === 'object' && module.exports) {
|
||||||
|
var nodeJS = true;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
factory(require, module);
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
// <script>
|
||||||
|
if(typeof forge === 'undefined') {
|
||||||
|
forge = {};
|
||||||
|
}
|
||||||
|
return initModule(forge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// AMD
|
||||||
|
var deps;
|
||||||
|
var defineFunc = function(require, module) {
|
||||||
|
module.exports = function(forge) {
|
||||||
|
var mods = deps.map(function(dep) {
|
||||||
|
return require(dep);
|
||||||
|
}).concat(initModule);
|
||||||
|
// handle circular dependencies
|
||||||
|
forge = forge || {};
|
||||||
|
forge.defined = forge.defined || {};
|
||||||
|
if(forge.defined[name]) {
|
||||||
|
return forge[name];
|
||||||
|
}
|
||||||
|
forge.defined[name] = true;
|
||||||
|
for(var i = 0; i < mods.length; ++i) {
|
||||||
|
mods[i](forge);
|
||||||
|
}
|
||||||
|
return forge[name];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
var tmpDefine = define;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
|
||||||
|
if(nodeJS) {
|
||||||
|
delete define;
|
||||||
|
return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
}
|
||||||
|
define = tmpDefine;
|
||||||
|
return define.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
};
|
||||||
|
define(['require', 'module', './aes', './tls'], function() {
|
||||||
|
defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
});
|
||||||
|
})();
|
||||||
1157
forge.js/asn1.js
Normal file
286
forge.js/cipher.js
Normal file
@@ -0,0 +1,286 @@
|
|||||||
|
/**
|
||||||
|
* Cipher base API.
|
||||||
|
*
|
||||||
|
* @author Dave Longley
|
||||||
|
*
|
||||||
|
* Copyright (c) 2010-2014 Digital Bazaar, Inc.
|
||||||
|
*/
|
||||||
|
(function() {
|
||||||
|
/* ########## Begin module implementation ########## */
|
||||||
|
function initModule(forge) {
|
||||||
|
|
||||||
|
forge.cipher = forge.cipher || {};
|
||||||
|
|
||||||
|
// registered algorithms
|
||||||
|
forge.cipher.algorithms = forge.cipher.algorithms || {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a cipher object that can be used to encrypt data using the given
|
||||||
|
* algorithm and key. The algorithm may be provided as a string value for a
|
||||||
|
* previously registered algorithm or it may be given as a cipher algorithm
|
||||||
|
* API object.
|
||||||
|
*
|
||||||
|
* @param algorithm the algorithm to use, either a string or an algorithm API
|
||||||
|
* object.
|
||||||
|
* @param key the key to use, as a binary-encoded string of bytes or a
|
||||||
|
* byte buffer.
|
||||||
|
*
|
||||||
|
* @return the cipher.
|
||||||
|
*/
|
||||||
|
forge.cipher.createCipher = function(algorithm, key) {
|
||||||
|
var api = algorithm;
|
||||||
|
if(typeof api === 'string') {
|
||||||
|
api = forge.cipher.getAlgorithm(api);
|
||||||
|
if(api) {
|
||||||
|
api = api();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!api) {
|
||||||
|
throw new Error('Unsupported algorithm: ' + algorithm);
|
||||||
|
}
|
||||||
|
|
||||||
|
// assume block cipher
|
||||||
|
return new forge.cipher.BlockCipher({
|
||||||
|
algorithm: api,
|
||||||
|
key: key,
|
||||||
|
decrypt: false
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a decipher object that can be used to decrypt data using the given
|
||||||
|
* algorithm and key. The algorithm may be provided as a string value for a
|
||||||
|
* previously registered algorithm or it may be given as a cipher algorithm
|
||||||
|
* API object.
|
||||||
|
*
|
||||||
|
* @param algorithm the algorithm to use, either a string or an algorithm API
|
||||||
|
* object.
|
||||||
|
* @param key the key to use, as a binary-encoded string of bytes or a
|
||||||
|
* byte buffer.
|
||||||
|
*
|
||||||
|
* @return the cipher.
|
||||||
|
*/
|
||||||
|
forge.cipher.createDecipher = function(algorithm, key) {
|
||||||
|
var api = algorithm;
|
||||||
|
if(typeof api === 'string') {
|
||||||
|
api = forge.cipher.getAlgorithm(api);
|
||||||
|
if(api) {
|
||||||
|
api = api();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!api) {
|
||||||
|
throw new Error('Unsupported algorithm: ' + algorithm);
|
||||||
|
}
|
||||||
|
|
||||||
|
// assume block cipher
|
||||||
|
return new forge.cipher.BlockCipher({
|
||||||
|
algorithm: api,
|
||||||
|
key: key,
|
||||||
|
decrypt: true
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers an algorithm by name. If the name was already registered, the
|
||||||
|
* algorithm API object will be overwritten.
|
||||||
|
*
|
||||||
|
* @param name the name of the algorithm.
|
||||||
|
* @param algorithm the algorithm API object.
|
||||||
|
*/
|
||||||
|
forge.cipher.registerAlgorithm = function(name, algorithm) {
|
||||||
|
name = name.toUpperCase();
|
||||||
|
forge.cipher.algorithms[name] = algorithm;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a registered algorithm by name.
|
||||||
|
*
|
||||||
|
* @param name the name of the algorithm.
|
||||||
|
*
|
||||||
|
* @return the algorithm, if found, null if not.
|
||||||
|
*/
|
||||||
|
forge.cipher.getAlgorithm = function(name) {
|
||||||
|
name = name.toUpperCase();
|
||||||
|
if(name in forge.cipher.algorithms) {
|
||||||
|
return forge.cipher.algorithms[name];
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
var BlockCipher = forge.cipher.BlockCipher = function(options) {
|
||||||
|
this.algorithm = options.algorithm;
|
||||||
|
this.mode = this.algorithm.mode;
|
||||||
|
this.blockSize = this.mode.blockSize;
|
||||||
|
this._finish = false;
|
||||||
|
this._input = null;
|
||||||
|
this.output = null;
|
||||||
|
this._op = options.decrypt ? this.mode.decrypt : this.mode.encrypt;
|
||||||
|
this._decrypt = options.decrypt;
|
||||||
|
this.algorithm.initialize(options);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts or restarts the encryption or decryption process, whichever
|
||||||
|
* was previously configured.
|
||||||
|
*
|
||||||
|
* For non-GCM mode, the IV may be a binary-encoded string of bytes, an array
|
||||||
|
* of bytes, a byte buffer, or an array of 32-bit integers. If the IV is in
|
||||||
|
* bytes, then it must be Nb (16) bytes in length. If the IV is given in as
|
||||||
|
* 32-bit integers, then it must be 4 integers long.
|
||||||
|
*
|
||||||
|
* Note: an IV is not required or used in ECB mode.
|
||||||
|
*
|
||||||
|
* For GCM-mode, the IV must be given as a binary-encoded string of bytes or
|
||||||
|
* a byte buffer. The number of bytes should be 12 (96 bits) as recommended
|
||||||
|
* by NIST SP-800-38D but another length may be given.
|
||||||
|
*
|
||||||
|
* @param options the options to use:
|
||||||
|
* iv the initialization vector to use as a binary-encoded string of
|
||||||
|
* bytes, null to reuse the last ciphered block from a previous
|
||||||
|
* update() (this "residue" method is for legacy support only).
|
||||||
|
* additionalData additional authentication data as a binary-encoded
|
||||||
|
* string of bytes, for 'GCM' mode, (default: none).
|
||||||
|
* tagLength desired length of authentication tag, in bits, for
|
||||||
|
* 'GCM' mode (0-128, default: 128).
|
||||||
|
* tag the authentication tag to check if decrypting, as a
|
||||||
|
* binary-encoded string of bytes.
|
||||||
|
* output the output the buffer to write to, null to create one.
|
||||||
|
*/
|
||||||
|
BlockCipher.prototype.start = function(options) {
|
||||||
|
options = options || {};
|
||||||
|
var opts = {};
|
||||||
|
for(var key in options) {
|
||||||
|
opts[key] = options[key];
|
||||||
|
}
|
||||||
|
opts.decrypt = this._decrypt;
|
||||||
|
this._finish = false;
|
||||||
|
this._input = forge.util.createBuffer();
|
||||||
|
this.output = options.output || forge.util.createBuffer();
|
||||||
|
this.mode.start(opts);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the next block according to the cipher mode.
|
||||||
|
*
|
||||||
|
* @param input the buffer to read from.
|
||||||
|
*/
|
||||||
|
BlockCipher.prototype.update = function(input) {
|
||||||
|
if(input) {
|
||||||
|
// input given, so empty it into the input buffer
|
||||||
|
this._input.putBuffer(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
// do cipher operation until it needs more input and not finished
|
||||||
|
while(!this._op.call(this.mode, this._input, this.output, this._finish) &&
|
||||||
|
!this._finish) {}
|
||||||
|
|
||||||
|
// free consumed memory from input buffer
|
||||||
|
this._input.compact();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finishes encrypting or decrypting.
|
||||||
|
*
|
||||||
|
* @param pad a padding function to use in CBC mode, null for default,
|
||||||
|
* signature(blockSize, buffer, decrypt).
|
||||||
|
*
|
||||||
|
* @return true if successful, false on error.
|
||||||
|
*/
|
||||||
|
BlockCipher.prototype.finish = function(pad) {
|
||||||
|
// backwards-compatibility w/deprecated padding API
|
||||||
|
// Note: will overwrite padding functions even after another start() call
|
||||||
|
if(pad && (this.mode.name === 'ECB' || this.mode.name === 'CBC')) {
|
||||||
|
this.mode.pad = function(input) {
|
||||||
|
return pad(this.blockSize, input, false);
|
||||||
|
};
|
||||||
|
this.mode.unpad = function(output) {
|
||||||
|
return pad(this.blockSize, output, true);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// build options for padding and afterFinish functions
|
||||||
|
var options = {};
|
||||||
|
options.decrypt = this._decrypt;
|
||||||
|
|
||||||
|
// get # of bytes that won't fill a block
|
||||||
|
options.overflow = this._input.length() % this.blockSize;
|
||||||
|
|
||||||
|
if(!this._decrypt && this.mode.pad) {
|
||||||
|
if(!this.mode.pad(this._input, options)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// do final update
|
||||||
|
this._finish = true;
|
||||||
|
this.update();
|
||||||
|
|
||||||
|
if(this._decrypt && this.mode.unpad) {
|
||||||
|
if(!this.mode.unpad(this.output, options)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this.mode.afterFinish) {
|
||||||
|
if(!this.mode.afterFinish(this.output, options)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // end module implementation
|
||||||
|
|
||||||
|
/* ########## Begin module wrapper ########## */
|
||||||
|
var name = 'cipher';
|
||||||
|
if(typeof define !== 'function') {
|
||||||
|
// NodeJS -> AMD
|
||||||
|
if(typeof module === 'object' && module.exports) {
|
||||||
|
var nodeJS = true;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
factory(require, module);
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
// <script>
|
||||||
|
if(typeof forge === 'undefined') {
|
||||||
|
forge = {};
|
||||||
|
}
|
||||||
|
return initModule(forge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// AMD
|
||||||
|
var deps;
|
||||||
|
var defineFunc = function(require, module) {
|
||||||
|
module.exports = function(forge) {
|
||||||
|
var mods = deps.map(function(dep) {
|
||||||
|
return require(dep);
|
||||||
|
}).concat(initModule);
|
||||||
|
// handle circular dependencies
|
||||||
|
forge = forge || {};
|
||||||
|
forge.defined = forge.defined || {};
|
||||||
|
if(forge.defined[name]) {
|
||||||
|
return forge[name];
|
||||||
|
}
|
||||||
|
forge.defined[name] = true;
|
||||||
|
for(var i = 0; i < mods.length; ++i) {
|
||||||
|
mods[i](forge);
|
||||||
|
}
|
||||||
|
return forge[name];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
var tmpDefine = define;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
|
||||||
|
if(nodeJS) {
|
||||||
|
delete define;
|
||||||
|
return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
}
|
||||||
|
define = tmpDefine;
|
||||||
|
return define.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
};
|
||||||
|
define(['require', 'module', './util'], function() {
|
||||||
|
defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
});
|
||||||
|
})();
|
||||||
1049
forge.js/cipherModes.js
Normal file
134
forge.js/debug.js
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
/**
|
||||||
|
* Debugging support for web applications.
|
||||||
|
*
|
||||||
|
* @author David I. Lehn <dlehn@digitalbazaar.com>
|
||||||
|
*
|
||||||
|
* Copyright 2008-2013 Digital Bazaar, Inc.
|
||||||
|
*/
|
||||||
|
(function() {
|
||||||
|
/* ########## Begin module implementation ########## */
|
||||||
|
function initModule(forge) {
|
||||||
|
|
||||||
|
/* DEBUG API */
|
||||||
|
forge.debug = forge.debug || {};
|
||||||
|
|
||||||
|
// Private storage for debugging.
|
||||||
|
// Useful to expose data that is otherwise unviewable behind closures.
|
||||||
|
// NOTE: remember that this can hold references to data and cause leaks!
|
||||||
|
// format is "forge._debug.<modulename>.<dataname> = data"
|
||||||
|
// Example:
|
||||||
|
// (function() {
|
||||||
|
// var cat = 'forge.test.Test'; // debugging category
|
||||||
|
// var sState = {...}; // local state
|
||||||
|
// forge.debug.set(cat, 'sState', sState);
|
||||||
|
// })();
|
||||||
|
forge.debug.storage = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets debug data. Omit name for all cat data Omit name and cat for
|
||||||
|
* all data.
|
||||||
|
*
|
||||||
|
* @param cat name of debugging category.
|
||||||
|
* @param name name of data to get (optional).
|
||||||
|
* @return object with requested debug data or undefined.
|
||||||
|
*/
|
||||||
|
forge.debug.get = function(cat, name) {
|
||||||
|
var rval;
|
||||||
|
if(typeof(cat) === 'undefined') {
|
||||||
|
rval = forge.debug.storage;
|
||||||
|
} else if(cat in forge.debug.storage) {
|
||||||
|
if(typeof(name) === 'undefined') {
|
||||||
|
rval = forge.debug.storage[cat];
|
||||||
|
} else {
|
||||||
|
rval = forge.debug.storage[cat][name];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rval;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets debug data.
|
||||||
|
*
|
||||||
|
* @param cat name of debugging category.
|
||||||
|
* @param name name of data to set.
|
||||||
|
* @param data data to set.
|
||||||
|
*/
|
||||||
|
forge.debug.set = function(cat, name, data) {
|
||||||
|
if(!(cat in forge.debug.storage)) {
|
||||||
|
forge.debug.storage[cat] = {};
|
||||||
|
}
|
||||||
|
forge.debug.storage[cat][name] = data;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears debug data. Omit name for all cat data. Omit name and cat for
|
||||||
|
* all data.
|
||||||
|
*
|
||||||
|
* @param cat name of debugging category.
|
||||||
|
* @param name name of data to clear or omit to clear entire category.
|
||||||
|
*/
|
||||||
|
forge.debug.clear = function(cat, name) {
|
||||||
|
if(typeof(cat) === 'undefined') {
|
||||||
|
forge.debug.storage = {};
|
||||||
|
} else if(cat in forge.debug.storage) {
|
||||||
|
if(typeof(name) === 'undefined') {
|
||||||
|
delete forge.debug.storage[cat];
|
||||||
|
} else {
|
||||||
|
delete forge.debug.storage[cat][name];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // end module implementation
|
||||||
|
|
||||||
|
/* ########## Begin module wrapper ########## */
|
||||||
|
var name = 'debug';
|
||||||
|
if(typeof define !== 'function') {
|
||||||
|
// NodeJS -> AMD
|
||||||
|
if(typeof module === 'object' && module.exports) {
|
||||||
|
var nodeJS = true;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
factory(require, module);
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
// <script>
|
||||||
|
if(typeof forge === 'undefined') {
|
||||||
|
forge = {};
|
||||||
|
}
|
||||||
|
return initModule(forge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// AMD
|
||||||
|
var deps;
|
||||||
|
var defineFunc = function(require, module) {
|
||||||
|
module.exports = function(forge) {
|
||||||
|
var mods = deps.map(function(dep) {
|
||||||
|
return require(dep);
|
||||||
|
}).concat(initModule);
|
||||||
|
// handle circular dependencies
|
||||||
|
forge = forge || {};
|
||||||
|
forge.defined = forge.defined || {};
|
||||||
|
if(forge.defined[name]) {
|
||||||
|
return forge[name];
|
||||||
|
}
|
||||||
|
forge.defined[name] = true;
|
||||||
|
for(var i = 0; i < mods.length; ++i) {
|
||||||
|
mods[i](forge);
|
||||||
|
}
|
||||||
|
return forge[name];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
var tmpDefine = define;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
|
||||||
|
if(nodeJS) {
|
||||||
|
delete define;
|
||||||
|
return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
}
|
||||||
|
define = tmpDefine;
|
||||||
|
return define.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
};
|
||||||
|
define(['require', 'module'], function() {
|
||||||
|
defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
});
|
||||||
|
})();
|
||||||
552
forge.js/des.js
Normal file
@@ -0,0 +1,552 @@
|
|||||||
|
/**
|
||||||
|
* DES (Data Encryption Standard) implementation.
|
||||||
|
*
|
||||||
|
* This implementation supports DES as well as 3DES-EDE in ECB and CBC mode.
|
||||||
|
* It is based on the BSD-licensed implementation by Paul Tero:
|
||||||
|
*
|
||||||
|
* Paul Tero, July 2001
|
||||||
|
* http://www.tero.co.uk/des/
|
||||||
|
*
|
||||||
|
* Optimised for performance with large blocks by Michael Hayworth, November 2001
|
||||||
|
* http://www.netdealing.com
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED "AS IS" AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* @author Stefan Siegl
|
||||||
|
* @author Dave Longley
|
||||||
|
*
|
||||||
|
* Copyright (c) 2012 Stefan Siegl <stesie@brokenpipe.de>
|
||||||
|
* Copyright (c) 2012-2014 Digital Bazaar, Inc.
|
||||||
|
*/
|
||||||
|
(function() {
|
||||||
|
/* ########## Begin module implementation ########## */
|
||||||
|
function initModule(forge) {
|
||||||
|
|
||||||
|
/* DES API */
|
||||||
|
forge.des = forge.des || {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deprecated. Instead, use:
|
||||||
|
*
|
||||||
|
* var cipher = forge.cipher.createCipher('DES-<mode>', key);
|
||||||
|
* cipher.start({iv: iv});
|
||||||
|
*
|
||||||
|
* Creates an DES cipher object to encrypt data using the given symmetric key.
|
||||||
|
* The output will be stored in the 'output' member of the returned cipher.
|
||||||
|
*
|
||||||
|
* The key and iv may be given as binary-encoded strings of bytes or
|
||||||
|
* byte buffers.
|
||||||
|
*
|
||||||
|
* @param key the symmetric key to use (64 or 192 bits).
|
||||||
|
* @param iv the initialization vector to use.
|
||||||
|
* @param output the buffer to write to, null to create one.
|
||||||
|
* @param mode the cipher mode to use (default: 'CBC' if IV is
|
||||||
|
* given, 'ECB' if null).
|
||||||
|
*
|
||||||
|
* @return the cipher.
|
||||||
|
*/
|
||||||
|
forge.des.startEncrypting = function(key, iv, output, mode) {
|
||||||
|
var cipher = _createCipher({
|
||||||
|
key: key,
|
||||||
|
output: output,
|
||||||
|
decrypt: false,
|
||||||
|
mode: mode || (iv === null ? 'ECB' : 'CBC')
|
||||||
|
});
|
||||||
|
cipher.start(iv);
|
||||||
|
return cipher;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deprecated. Instead, use:
|
||||||
|
*
|
||||||
|
* var cipher = forge.cipher.createCipher('DES-<mode>', key);
|
||||||
|
*
|
||||||
|
* Creates an DES cipher object to encrypt data using the given symmetric key.
|
||||||
|
*
|
||||||
|
* The key may be given as a binary-encoded string of bytes or a byte buffer.
|
||||||
|
*
|
||||||
|
* @param key the symmetric key to use (64 or 192 bits).
|
||||||
|
* @param mode the cipher mode to use (default: 'CBC').
|
||||||
|
*
|
||||||
|
* @return the cipher.
|
||||||
|
*/
|
||||||
|
forge.des.createEncryptionCipher = function(key, mode) {
|
||||||
|
return _createCipher({
|
||||||
|
key: key,
|
||||||
|
output: null,
|
||||||
|
decrypt: false,
|
||||||
|
mode: mode
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deprecated. Instead, use:
|
||||||
|
*
|
||||||
|
* var decipher = forge.cipher.createDecipher('DES-<mode>', key);
|
||||||
|
* decipher.start({iv: iv});
|
||||||
|
*
|
||||||
|
* Creates an DES cipher object to decrypt data using the given symmetric key.
|
||||||
|
* The output will be stored in the 'output' member of the returned cipher.
|
||||||
|
*
|
||||||
|
* The key and iv may be given as binary-encoded strings of bytes or
|
||||||
|
* byte buffers.
|
||||||
|
*
|
||||||
|
* @param key the symmetric key to use (64 or 192 bits).
|
||||||
|
* @param iv the initialization vector to use.
|
||||||
|
* @param output the buffer to write to, null to create one.
|
||||||
|
* @param mode the cipher mode to use (default: 'CBC' if IV is
|
||||||
|
* given, 'ECB' if null).
|
||||||
|
*
|
||||||
|
* @return the cipher.
|
||||||
|
*/
|
||||||
|
forge.des.startDecrypting = function(key, iv, output, mode) {
|
||||||
|
var cipher = _createCipher({
|
||||||
|
key: key,
|
||||||
|
output: output,
|
||||||
|
decrypt: true,
|
||||||
|
mode: mode || (iv === null ? 'ECB' : 'CBC')
|
||||||
|
});
|
||||||
|
cipher.start(iv);
|
||||||
|
return cipher;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deprecated. Instead, use:
|
||||||
|
*
|
||||||
|
* var decipher = forge.cipher.createDecipher('DES-<mode>', key);
|
||||||
|
*
|
||||||
|
* Creates an DES cipher object to decrypt data using the given symmetric key.
|
||||||
|
*
|
||||||
|
* The key may be given as a binary-encoded string of bytes or a byte buffer.
|
||||||
|
*
|
||||||
|
* @param key the symmetric key to use (64 or 192 bits).
|
||||||
|
* @param mode the cipher mode to use (default: 'CBC').
|
||||||
|
*
|
||||||
|
* @return the cipher.
|
||||||
|
*/
|
||||||
|
forge.des.createDecryptionCipher = function(key, mode) {
|
||||||
|
return _createCipher({
|
||||||
|
key: key,
|
||||||
|
output: null,
|
||||||
|
decrypt: true,
|
||||||
|
mode: mode
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new DES cipher algorithm object.
|
||||||
|
*
|
||||||
|
* @param name the name of the algorithm.
|
||||||
|
* @param mode the mode factory function.
|
||||||
|
*
|
||||||
|
* @return the DES algorithm object.
|
||||||
|
*/
|
||||||
|
forge.des.Algorithm = function(name, mode) {
|
||||||
|
var self = this;
|
||||||
|
self.name = name;
|
||||||
|
self.mode = new mode({
|
||||||
|
blockSize: 8,
|
||||||
|
cipher: {
|
||||||
|
encrypt: function(inBlock, outBlock) {
|
||||||
|
return _updateBlock(self._keys, inBlock, outBlock, false);
|
||||||
|
},
|
||||||
|
decrypt: function(inBlock, outBlock) {
|
||||||
|
return _updateBlock(self._keys, inBlock, outBlock, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
self._init = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes this DES algorithm by expanding its key.
|
||||||
|
*
|
||||||
|
* @param options the options to use.
|
||||||
|
* key the key to use with this algorithm.
|
||||||
|
* decrypt true if the algorithm should be initialized for decryption,
|
||||||
|
* false for encryption.
|
||||||
|
*/
|
||||||
|
forge.des.Algorithm.prototype.initialize = function(options) {
|
||||||
|
if(this._init) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var key = forge.util.createBuffer(options.key);
|
||||||
|
if(this.name.indexOf('3DES') === 0) {
|
||||||
|
if(key.length() !== 24) {
|
||||||
|
throw new Error('Invalid Triple-DES key size: ' + key.length() * 8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// do key expansion to 16 or 48 subkeys (single or triple DES)
|
||||||
|
this._keys = _createKeys(key);
|
||||||
|
this._init = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/** Register DES algorithms **/
|
||||||
|
|
||||||
|
registerAlgorithm('DES-ECB', forge.cipher.modes.ecb);
|
||||||
|
registerAlgorithm('DES-CBC', forge.cipher.modes.cbc);
|
||||||
|
registerAlgorithm('DES-CFB', forge.cipher.modes.cfb);
|
||||||
|
registerAlgorithm('DES-OFB', forge.cipher.modes.ofb);
|
||||||
|
registerAlgorithm('DES-CTR', forge.cipher.modes.ctr);
|
||||||
|
|
||||||
|
registerAlgorithm('3DES-ECB', forge.cipher.modes.ecb);
|
||||||
|
registerAlgorithm('3DES-CBC', forge.cipher.modes.cbc);
|
||||||
|
registerAlgorithm('3DES-CFB', forge.cipher.modes.cfb);
|
||||||
|
registerAlgorithm('3DES-OFB', forge.cipher.modes.ofb);
|
||||||
|
registerAlgorithm('3DES-CTR', forge.cipher.modes.ctr);
|
||||||
|
|
||||||
|
function registerAlgorithm(name, mode) {
|
||||||
|
var factory = function() {
|
||||||
|
return new forge.des.Algorithm(name, mode);
|
||||||
|
};
|
||||||
|
forge.cipher.registerAlgorithm(name, factory);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** DES implementation **/
|
||||||
|
|
||||||
|
var spfunction1 = [0x1010400,0,0x10000,0x1010404,0x1010004,0x10404,0x4,0x10000,0x400,0x1010400,0x1010404,0x400,0x1000404,0x1010004,0x1000000,0x4,0x404,0x1000400,0x1000400,0x10400,0x10400,0x1010000,0x1010000,0x1000404,0x10004,0x1000004,0x1000004,0x10004,0,0x404,0x10404,0x1000000,0x10000,0x1010404,0x4,0x1010000,0x1010400,0x1000000,0x1000000,0x400,0x1010004,0x10000,0x10400,0x1000004,0x400,0x4,0x1000404,0x10404,0x1010404,0x10004,0x1010000,0x1000404,0x1000004,0x404,0x10404,0x1010400,0x404,0x1000400,0x1000400,0,0x10004,0x10400,0,0x1010004];
|
||||||
|
var spfunction2 = [-0x7fef7fe0,-0x7fff8000,0x8000,0x108020,0x100000,0x20,-0x7fefffe0,-0x7fff7fe0,-0x7fffffe0,-0x7fef7fe0,-0x7fef8000,-0x80000000,-0x7fff8000,0x100000,0x20,-0x7fefffe0,0x108000,0x100020,-0x7fff7fe0,0,-0x80000000,0x8000,0x108020,-0x7ff00000,0x100020,-0x7fffffe0,0,0x108000,0x8020,-0x7fef8000,-0x7ff00000,0x8020,0,0x108020,-0x7fefffe0,0x100000,-0x7fff7fe0,-0x7ff00000,-0x7fef8000,0x8000,-0x7ff00000,-0x7fff8000,0x20,-0x7fef7fe0,0x108020,0x20,0x8000,-0x80000000,0x8020,-0x7fef8000,0x100000,-0x7fffffe0,0x100020,-0x7fff7fe0,-0x7fffffe0,0x100020,0x108000,0,-0x7fff8000,0x8020,-0x80000000,-0x7fefffe0,-0x7fef7fe0,0x108000];
|
||||||
|
var spfunction3 = [0x208,0x8020200,0,0x8020008,0x8000200,0,0x20208,0x8000200,0x20008,0x8000008,0x8000008,0x20000,0x8020208,0x20008,0x8020000,0x208,0x8000000,0x8,0x8020200,0x200,0x20200,0x8020000,0x8020008,0x20208,0x8000208,0x20200,0x20000,0x8000208,0x8,0x8020208,0x200,0x8000000,0x8020200,0x8000000,0x20008,0x208,0x20000,0x8020200,0x8000200,0,0x200,0x20008,0x8020208,0x8000200,0x8000008,0x200,0,0x8020008,0x8000208,0x20000,0x8000000,0x8020208,0x8,0x20208,0x20200,0x8000008,0x8020000,0x8000208,0x208,0x8020000,0x20208,0x8,0x8020008,0x20200];
|
||||||
|
var spfunction4 = [0x802001,0x2081,0x2081,0x80,0x802080,0x800081,0x800001,0x2001,0,0x802000,0x802000,0x802081,0x81,0,0x800080,0x800001,0x1,0x2000,0x800000,0x802001,0x80,0x800000,0x2001,0x2080,0x800081,0x1,0x2080,0x800080,0x2000,0x802080,0x802081,0x81,0x800080,0x800001,0x802000,0x802081,0x81,0,0,0x802000,0x2080,0x800080,0x800081,0x1,0x802001,0x2081,0x2081,0x80,0x802081,0x81,0x1,0x2000,0x800001,0x2001,0x802080,0x800081,0x2001,0x2080,0x800000,0x802001,0x80,0x800000,0x2000,0x802080];
|
||||||
|
var spfunction5 = [0x100,0x2080100,0x2080000,0x42000100,0x80000,0x100,0x40000000,0x2080000,0x40080100,0x80000,0x2000100,0x40080100,0x42000100,0x42080000,0x80100,0x40000000,0x2000000,0x40080000,0x40080000,0,0x40000100,0x42080100,0x42080100,0x2000100,0x42080000,0x40000100,0,0x42000000,0x2080100,0x2000000,0x42000000,0x80100,0x80000,0x42000100,0x100,0x2000000,0x40000000,0x2080000,0x42000100,0x40080100,0x2000100,0x40000000,0x42080000,0x2080100,0x40080100,0x100,0x2000000,0x42080000,0x42080100,0x80100,0x42000000,0x42080100,0x2080000,0,0x40080000,0x42000000,0x80100,0x2000100,0x40000100,0x80000,0,0x40080000,0x2080100,0x40000100];
|
||||||
|
var spfunction6 = [0x20000010,0x20400000,0x4000,0x20404010,0x20400000,0x10,0x20404010,0x400000,0x20004000,0x404010,0x400000,0x20000010,0x400010,0x20004000,0x20000000,0x4010,0,0x400010,0x20004010,0x4000,0x404000,0x20004010,0x10,0x20400010,0x20400010,0,0x404010,0x20404000,0x4010,0x404000,0x20404000,0x20000000,0x20004000,0x10,0x20400010,0x404000,0x20404010,0x400000,0x4010,0x20000010,0x400000,0x20004000,0x20000000,0x4010,0x20000010,0x20404010,0x404000,0x20400000,0x404010,0x20404000,0,0x20400010,0x10,0x4000,0x20400000,0x404010,0x4000,0x400010,0x20004010,0,0x20404000,0x20000000,0x400010,0x20004010];
|
||||||
|
var spfunction7 = [0x200000,0x4200002,0x4000802,0,0x800,0x4000802,0x200802,0x4200800,0x4200802,0x200000,0,0x4000002,0x2,0x4000000,0x4200002,0x802,0x4000800,0x200802,0x200002,0x4000800,0x4000002,0x4200000,0x4200800,0x200002,0x4200000,0x800,0x802,0x4200802,0x200800,0x2,0x4000000,0x200800,0x4000000,0x200800,0x200000,0x4000802,0x4000802,0x4200002,0x4200002,0x2,0x200002,0x4000000,0x4000800,0x200000,0x4200800,0x802,0x200802,0x4200800,0x802,0x4000002,0x4200802,0x4200000,0x200800,0,0x2,0x4200802,0,0x200802,0x4200000,0x800,0x4000002,0x4000800,0x800,0x200002];
|
||||||
|
var spfunction8 = [0x10001040,0x1000,0x40000,0x10041040,0x10000000,0x10001040,0x40,0x10000000,0x40040,0x10040000,0x10041040,0x41000,0x10041000,0x41040,0x1000,0x40,0x10040000,0x10000040,0x10001000,0x1040,0x41000,0x40040,0x10040040,0x10041000,0x1040,0,0,0x10040040,0x10000040,0x10001000,0x41040,0x40000,0x41040,0x40000,0x10041000,0x1000,0x40,0x10040040,0x1000,0x41040,0x10001000,0x40,0x10000040,0x10040000,0x10040040,0x10000000,0x40000,0x10001040,0,0x10041040,0x40040,0x10000040,0x10040000,0x10001000,0x10001040,0,0x10041040,0x41000,0x41000,0x1040,0x1040,0x40040,0x10000000,0x10041000];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create necessary sub keys.
|
||||||
|
*
|
||||||
|
* @param key the 64-bit or 192-bit key.
|
||||||
|
*
|
||||||
|
* @return the expanded keys.
|
||||||
|
*/
|
||||||
|
function _createKeys(key) {
|
||||||
|
var pc2bytes0 = [0,0x4,0x20000000,0x20000004,0x10000,0x10004,0x20010000,0x20010004,0x200,0x204,0x20000200,0x20000204,0x10200,0x10204,0x20010200,0x20010204],
|
||||||
|
pc2bytes1 = [0,0x1,0x100000,0x100001,0x4000000,0x4000001,0x4100000,0x4100001,0x100,0x101,0x100100,0x100101,0x4000100,0x4000101,0x4100100,0x4100101],
|
||||||
|
pc2bytes2 = [0,0x8,0x800,0x808,0x1000000,0x1000008,0x1000800,0x1000808,0,0x8,0x800,0x808,0x1000000,0x1000008,0x1000800,0x1000808],
|
||||||
|
pc2bytes3 = [0,0x200000,0x8000000,0x8200000,0x2000,0x202000,0x8002000,0x8202000,0x20000,0x220000,0x8020000,0x8220000,0x22000,0x222000,0x8022000,0x8222000],
|
||||||
|
pc2bytes4 = [0,0x40000,0x10,0x40010,0,0x40000,0x10,0x40010,0x1000,0x41000,0x1010,0x41010,0x1000,0x41000,0x1010,0x41010],
|
||||||
|
pc2bytes5 = [0,0x400,0x20,0x420,0,0x400,0x20,0x420,0x2000000,0x2000400,0x2000020,0x2000420,0x2000000,0x2000400,0x2000020,0x2000420],
|
||||||
|
pc2bytes6 = [0,0x10000000,0x80000,0x10080000,0x2,0x10000002,0x80002,0x10080002,0,0x10000000,0x80000,0x10080000,0x2,0x10000002,0x80002,0x10080002],
|
||||||
|
pc2bytes7 = [0,0x10000,0x800,0x10800,0x20000000,0x20010000,0x20000800,0x20010800,0x20000,0x30000,0x20800,0x30800,0x20020000,0x20030000,0x20020800,0x20030800],
|
||||||
|
pc2bytes8 = [0,0x40000,0,0x40000,0x2,0x40002,0x2,0x40002,0x2000000,0x2040000,0x2000000,0x2040000,0x2000002,0x2040002,0x2000002,0x2040002],
|
||||||
|
pc2bytes9 = [0,0x10000000,0x8,0x10000008,0,0x10000000,0x8,0x10000008,0x400,0x10000400,0x408,0x10000408,0x400,0x10000400,0x408,0x10000408],
|
||||||
|
pc2bytes10 = [0,0x20,0,0x20,0x100000,0x100020,0x100000,0x100020,0x2000,0x2020,0x2000,0x2020,0x102000,0x102020,0x102000,0x102020],
|
||||||
|
pc2bytes11 = [0,0x1000000,0x200,0x1000200,0x200000,0x1200000,0x200200,0x1200200,0x4000000,0x5000000,0x4000200,0x5000200,0x4200000,0x5200000,0x4200200,0x5200200],
|
||||||
|
pc2bytes12 = [0,0x1000,0x8000000,0x8001000,0x80000,0x81000,0x8080000,0x8081000,0x10,0x1010,0x8000010,0x8001010,0x80010,0x81010,0x8080010,0x8081010],
|
||||||
|
pc2bytes13 = [0,0x4,0x100,0x104,0,0x4,0x100,0x104,0x1,0x5,0x101,0x105,0x1,0x5,0x101,0x105];
|
||||||
|
|
||||||
|
// how many iterations (1 for des, 3 for triple des)
|
||||||
|
// changed by Paul 16/6/2007 to use Triple DES for 9+ byte keys
|
||||||
|
var iterations = key.length() > 8 ? 3 : 1;
|
||||||
|
|
||||||
|
// stores the return keys
|
||||||
|
var keys = [];
|
||||||
|
|
||||||
|
// now define the left shifts which need to be done
|
||||||
|
var shifts = [0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0];
|
||||||
|
|
||||||
|
var n = 0, tmp;
|
||||||
|
for(var j = 0; j < iterations; j ++) {
|
||||||
|
var left = key.getInt32();
|
||||||
|
var right = key.getInt32();
|
||||||
|
|
||||||
|
tmp = ((left >>> 4) ^ right) & 0x0f0f0f0f;
|
||||||
|
right ^= tmp;
|
||||||
|
left ^= (tmp << 4);
|
||||||
|
|
||||||
|
tmp = ((right >>> -16) ^ left) & 0x0000ffff;
|
||||||
|
left ^= tmp;
|
||||||
|
right ^= (tmp << -16);
|
||||||
|
|
||||||
|
tmp = ((left >>> 2) ^ right) & 0x33333333;
|
||||||
|
right ^= tmp;
|
||||||
|
left ^= (tmp << 2);
|
||||||
|
|
||||||
|
tmp = ((right >>> -16) ^ left) & 0x0000ffff;
|
||||||
|
left ^= tmp;
|
||||||
|
right ^= (tmp << -16);
|
||||||
|
|
||||||
|
tmp = ((left >>> 1) ^ right) & 0x55555555;
|
||||||
|
right ^= tmp;
|
||||||
|
left ^= (tmp << 1);
|
||||||
|
|
||||||
|
tmp = ((right >>> 8) ^ left) & 0x00ff00ff;
|
||||||
|
left ^= tmp;
|
||||||
|
right ^= (tmp << 8);
|
||||||
|
|
||||||
|
tmp = ((left >>> 1) ^ right) & 0x55555555;
|
||||||
|
right ^= tmp;
|
||||||
|
left ^= (tmp << 1);
|
||||||
|
|
||||||
|
// right needs to be shifted and OR'd with last four bits of left
|
||||||
|
tmp = (left << 8) | ((right >>> 20) & 0x000000f0);
|
||||||
|
|
||||||
|
// left needs to be put upside down
|
||||||
|
left = ((right << 24) | ((right << 8) & 0xff0000) |
|
||||||
|
((right >>> 8) & 0xff00) | ((right >>> 24) & 0xf0));
|
||||||
|
right = tmp;
|
||||||
|
|
||||||
|
// now go through and perform these shifts on the left and right keys
|
||||||
|
for(var i = 0; i < shifts.length; ++i) {
|
||||||
|
//shift the keys either one or two bits to the left
|
||||||
|
if(shifts[i]) {
|
||||||
|
left = (left << 2) | (left >>> 26);
|
||||||
|
right = (right << 2) | (right >>> 26);
|
||||||
|
} else {
|
||||||
|
left = (left << 1) | (left >>> 27);
|
||||||
|
right = (right << 1) | (right >>> 27);
|
||||||
|
}
|
||||||
|
left &= -0xf;
|
||||||
|
right &= -0xf;
|
||||||
|
|
||||||
|
// now apply PC-2, in such a way that E is easier when encrypting or
|
||||||
|
// decrypting this conversion will look like PC-2 except only the last 6
|
||||||
|
// bits of each byte are used rather than 48 consecutive bits and the
|
||||||
|
// order of lines will be according to how the S selection functions will
|
||||||
|
// be applied: S2, S4, S6, S8, S1, S3, S5, S7
|
||||||
|
var lefttmp = (
|
||||||
|
pc2bytes0[left >>> 28] | pc2bytes1[(left >>> 24) & 0xf] |
|
||||||
|
pc2bytes2[(left >>> 20) & 0xf] | pc2bytes3[(left >>> 16) & 0xf] |
|
||||||
|
pc2bytes4[(left >>> 12) & 0xf] | pc2bytes5[(left >>> 8) & 0xf] |
|
||||||
|
pc2bytes6[(left >>> 4) & 0xf]);
|
||||||
|
var righttmp = (
|
||||||
|
pc2bytes7[right >>> 28] | pc2bytes8[(right >>> 24) & 0xf] |
|
||||||
|
pc2bytes9[(right >>> 20) & 0xf] | pc2bytes10[(right >>> 16) & 0xf] |
|
||||||
|
pc2bytes11[(right >>> 12) & 0xf] | pc2bytes12[(right >>> 8) & 0xf] |
|
||||||
|
pc2bytes13[(right >>> 4) & 0xf]);
|
||||||
|
tmp = ((righttmp >>> 16) ^ lefttmp) & 0x0000ffff;
|
||||||
|
keys[n++] = lefttmp ^ tmp;
|
||||||
|
keys[n++] = righttmp ^ (tmp << 16);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return keys;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates a single block (1 byte) using DES. The update will either
|
||||||
|
* encrypt or decrypt the block.
|
||||||
|
*
|
||||||
|
* @param keys the expanded keys.
|
||||||
|
* @param input the input block (an array of 32-bit words).
|
||||||
|
* @param output the updated output block.
|
||||||
|
* @param decrypt true to decrypt the block, false to encrypt it.
|
||||||
|
*/
|
||||||
|
function _updateBlock(keys, input, output, decrypt) {
|
||||||
|
// set up loops for single or triple DES
|
||||||
|
var iterations = keys.length === 32 ? 3 : 9;
|
||||||
|
var looping;
|
||||||
|
if(iterations === 3) {
|
||||||
|
looping = decrypt ? [30, -2, -2] : [0, 32, 2];
|
||||||
|
} else {
|
||||||
|
looping = (decrypt ?
|
||||||
|
[94, 62, -2, 32, 64, 2, 30, -2, -2] :
|
||||||
|
[0, 32, 2, 62, 30, -2, 64, 96, 2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
var tmp;
|
||||||
|
|
||||||
|
var left = input[0];
|
||||||
|
var right = input[1];
|
||||||
|
|
||||||
|
// first each 64 bit chunk of the message must be permuted according to IP
|
||||||
|
tmp = ((left >>> 4) ^ right) & 0x0f0f0f0f;
|
||||||
|
right ^= tmp;
|
||||||
|
left ^= (tmp << 4);
|
||||||
|
|
||||||
|
tmp = ((left >>> 16) ^ right) & 0x0000ffff;
|
||||||
|
right ^= tmp;
|
||||||
|
left ^= (tmp << 16);
|
||||||
|
|
||||||
|
tmp = ((right >>> 2) ^ left) & 0x33333333;
|
||||||
|
left ^= tmp;
|
||||||
|
right ^= (tmp << 2);
|
||||||
|
|
||||||
|
tmp = ((right >>> 8) ^ left) & 0x00ff00ff;
|
||||||
|
left ^= tmp;
|
||||||
|
right ^= (tmp << 8);
|
||||||
|
|
||||||
|
tmp = ((left >>> 1) ^ right) & 0x55555555;
|
||||||
|
right ^= tmp;
|
||||||
|
left ^= (tmp << 1);
|
||||||
|
|
||||||
|
// rotate left 1 bit
|
||||||
|
left = ((left << 1) | (left >>> 31));
|
||||||
|
right = ((right << 1) | (right >>> 31));
|
||||||
|
|
||||||
|
for(var j = 0; j < iterations; j += 3) {
|
||||||
|
var endloop = looping[j + 1];
|
||||||
|
var loopinc = looping[j + 2];
|
||||||
|
|
||||||
|
// now go through and perform the encryption or decryption
|
||||||
|
for(var i = looping[j]; i != endloop; i += loopinc) {
|
||||||
|
var right1 = right ^ keys[i];
|
||||||
|
var right2 = ((right >>> 4) | (right << 28)) ^ keys[i + 1];
|
||||||
|
|
||||||
|
// passing these bytes through the S selection functions
|
||||||
|
tmp = left;
|
||||||
|
left = right;
|
||||||
|
right = tmp ^ (
|
||||||
|
spfunction2[(right1 >>> 24) & 0x3f] |
|
||||||
|
spfunction4[(right1 >>> 16) & 0x3f] |
|
||||||
|
spfunction6[(right1 >>> 8) & 0x3f] |
|
||||||
|
spfunction8[right1 & 0x3f] |
|
||||||
|
spfunction1[(right2 >>> 24) & 0x3f] |
|
||||||
|
spfunction3[(right2 >>> 16) & 0x3f] |
|
||||||
|
spfunction5[(right2 >>> 8) & 0x3f] |
|
||||||
|
spfunction7[right2 & 0x3f]);
|
||||||
|
}
|
||||||
|
// unreverse left and right
|
||||||
|
tmp = left;
|
||||||
|
left = right;
|
||||||
|
right = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// rotate right 1 bit
|
||||||
|
left = ((left >>> 1) | (left << 31));
|
||||||
|
right = ((right >>> 1) | (right << 31));
|
||||||
|
|
||||||
|
// now perform IP-1, which is IP in the opposite direction
|
||||||
|
tmp = ((left >>> 1) ^ right) & 0x55555555;
|
||||||
|
right ^= tmp;
|
||||||
|
left ^= (tmp << 1);
|
||||||
|
|
||||||
|
tmp = ((right >>> 8) ^ left) & 0x00ff00ff;
|
||||||
|
left ^= tmp;
|
||||||
|
right ^= (tmp << 8);
|
||||||
|
|
||||||
|
tmp = ((right >>> 2) ^ left) & 0x33333333;
|
||||||
|
left ^= tmp;
|
||||||
|
right ^= (tmp << 2);
|
||||||
|
|
||||||
|
tmp = ((left >>> 16) ^ right) & 0x0000ffff;
|
||||||
|
right ^= tmp;
|
||||||
|
left ^= (tmp << 16);
|
||||||
|
|
||||||
|
tmp = ((left >>> 4) ^ right) & 0x0f0f0f0f;
|
||||||
|
right ^= tmp;
|
||||||
|
left ^= (tmp << 4);
|
||||||
|
|
||||||
|
output[0] = left;
|
||||||
|
output[1] = right;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deprecated. Instead, use:
|
||||||
|
*
|
||||||
|
* forge.cipher.createCipher('DES-<mode>', key);
|
||||||
|
* forge.cipher.createDecipher('DES-<mode>', key);
|
||||||
|
*
|
||||||
|
* Creates a deprecated DES cipher object. This object's mode will default to
|
||||||
|
* CBC (cipher-block-chaining).
|
||||||
|
*
|
||||||
|
* The key may be given as a binary-encoded string of bytes or a byte buffer.
|
||||||
|
*
|
||||||
|
* @param options the options to use.
|
||||||
|
* key the symmetric key to use (64 or 192 bits).
|
||||||
|
* output the buffer to write to.
|
||||||
|
* decrypt true for decryption, false for encryption.
|
||||||
|
* mode the cipher mode to use (default: 'CBC').
|
||||||
|
*
|
||||||
|
* @return the cipher.
|
||||||
|
*/
|
||||||
|
function _createCipher(options) {
|
||||||
|
options = options || {};
|
||||||
|
var mode = (options.mode || 'CBC').toUpperCase();
|
||||||
|
var algorithm = 'DES-' + mode;
|
||||||
|
|
||||||
|
var cipher;
|
||||||
|
if(options.decrypt) {
|
||||||
|
cipher = forge.cipher.createDecipher(algorithm, options.key);
|
||||||
|
} else {
|
||||||
|
cipher = forge.cipher.createCipher(algorithm, options.key);
|
||||||
|
}
|
||||||
|
|
||||||
|
// backwards compatible start API
|
||||||
|
var start = cipher.start;
|
||||||
|
cipher.start = function(iv, options) {
|
||||||
|
// backwards compatibility: support second arg as output buffer
|
||||||
|
var output = null;
|
||||||
|
if(options instanceof forge.util.ByteBuffer) {
|
||||||
|
output = options;
|
||||||
|
options = {};
|
||||||
|
}
|
||||||
|
options = options || {};
|
||||||
|
options.output = output;
|
||||||
|
options.iv = iv;
|
||||||
|
start.call(cipher, options);
|
||||||
|
};
|
||||||
|
|
||||||
|
return cipher;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // end module implementation
|
||||||
|
|
||||||
|
/* ########## Begin module wrapper ########## */
|
||||||
|
var name = 'des';
|
||||||
|
if(typeof define !== 'function') {
|
||||||
|
// NodeJS -> AMD
|
||||||
|
if(typeof module === 'object' && module.exports) {
|
||||||
|
var nodeJS = true;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
factory(require, module);
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
// <script>
|
||||||
|
if(typeof forge === 'undefined') {
|
||||||
|
forge = {};
|
||||||
|
}
|
||||||
|
return initModule(forge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// AMD
|
||||||
|
var deps;
|
||||||
|
var defineFunc = function(require, module) {
|
||||||
|
module.exports = function(forge) {
|
||||||
|
var mods = deps.map(function(dep) {
|
||||||
|
return require(dep);
|
||||||
|
}).concat(initModule);
|
||||||
|
// handle circular dependencies
|
||||||
|
forge = forge || {};
|
||||||
|
forge.defined = forge.defined || {};
|
||||||
|
if(forge.defined[name]) {
|
||||||
|
return forge[name];
|
||||||
|
}
|
||||||
|
forge.defined[name] = true;
|
||||||
|
for(var i = 0; i < mods.length; ++i) {
|
||||||
|
mods[i](forge);
|
||||||
|
}
|
||||||
|
return forge[name];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
var tmpDefine = define;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
|
||||||
|
if(nodeJS) {
|
||||||
|
delete define;
|
||||||
|
return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
}
|
||||||
|
define = tmpDefine;
|
||||||
|
return define.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
};
|
||||||
|
define(
|
||||||
|
['require', 'module', './cipher', './cipherModes', './util'], function() {
|
||||||
|
defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
});
|
||||||
|
})();
|
||||||
29553
forge.js/forge.bundle.js
Normal file
92
forge.js/forge.js
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
/**
|
||||||
|
* Node.js module for Forge.
|
||||||
|
*
|
||||||
|
* @author Dave Longley
|
||||||
|
*
|
||||||
|
* Copyright 2011-2014 Digital Bazaar, Inc.
|
||||||
|
*/
|
||||||
|
(function() {
|
||||||
|
var name = 'forge';
|
||||||
|
if(typeof define !== 'function') {
|
||||||
|
// NodeJS -> AMD
|
||||||
|
if(typeof module === 'object' && module.exports) {
|
||||||
|
var nodeJS = true;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
factory(require, module);
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
// <script>
|
||||||
|
if(typeof forge === 'undefined') {
|
||||||
|
// set to true to disable native code if even it's available
|
||||||
|
forge = {disableNativeCode: false};
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// AMD
|
||||||
|
var deps;
|
||||||
|
var defineFunc = function(require, module) {
|
||||||
|
module.exports = function(forge) {
|
||||||
|
var mods = deps.map(function(dep) {
|
||||||
|
return require(dep);
|
||||||
|
});
|
||||||
|
// handle circular dependencies
|
||||||
|
forge = forge || {};
|
||||||
|
forge.defined = forge.defined || {};
|
||||||
|
if(forge.defined[name]) {
|
||||||
|
return forge[name];
|
||||||
|
}
|
||||||
|
forge.defined[name] = true;
|
||||||
|
for(var i = 0; i < mods.length; ++i) {
|
||||||
|
mods[i](forge);
|
||||||
|
}
|
||||||
|
return forge;
|
||||||
|
};
|
||||||
|
// set to true to disable native code if even it's available
|
||||||
|
module.exports.disableNativeCode = false;
|
||||||
|
module.exports(module.exports);
|
||||||
|
};
|
||||||
|
var tmpDefine = define;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
|
||||||
|
if(nodeJS) {
|
||||||
|
delete define;
|
||||||
|
return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
}
|
||||||
|
define = tmpDefine;
|
||||||
|
return define.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
};
|
||||||
|
define([
|
||||||
|
'require',
|
||||||
|
'module',
|
||||||
|
'./aes',
|
||||||
|
'./aesCipherSuites',
|
||||||
|
'./asn1',
|
||||||
|
'./cipher',
|
||||||
|
'./cipherModes',
|
||||||
|
'./debug',
|
||||||
|
'./des',
|
||||||
|
'./hmac',
|
||||||
|
'./kem',
|
||||||
|
'./log',
|
||||||
|
'./md',
|
||||||
|
'./mgf1',
|
||||||
|
'./pbkdf2',
|
||||||
|
'./pem',
|
||||||
|
'./pkcs7',
|
||||||
|
'./pkcs1',
|
||||||
|
'./pkcs12',
|
||||||
|
'./pki',
|
||||||
|
'./prime',
|
||||||
|
'./prng',
|
||||||
|
'./pss',
|
||||||
|
'./random',
|
||||||
|
'./rc2',
|
||||||
|
'./ssh',
|
||||||
|
'./task',
|
||||||
|
'./tls',
|
||||||
|
'./util'
|
||||||
|
], function() {
|
||||||
|
defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
});
|
||||||
|
})();
|
||||||
157
forge.js/form.js
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
/**
|
||||||
|
* Functions for manipulating web forms.
|
||||||
|
*
|
||||||
|
* @author David I. Lehn <dlehn@digitalbazaar.com>
|
||||||
|
* @author Dave Longley
|
||||||
|
* @author Mike Johnson
|
||||||
|
*
|
||||||
|
* Copyright (c) 2011-2014 Digital Bazaar, Inc. All rights reserved.
|
||||||
|
*/
|
||||||
|
(function($) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The form namespace.
|
||||||
|
*/
|
||||||
|
var form = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Regex for parsing a single name property (handles array brackets).
|
||||||
|
*/
|
||||||
|
var _regex = /(.*?)\[(.*?)\]/g;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a single name property into an array with the name and any
|
||||||
|
* array indices.
|
||||||
|
*
|
||||||
|
* @param name the name to parse.
|
||||||
|
*
|
||||||
|
* @return the array of the name and its array indices in order.
|
||||||
|
*/
|
||||||
|
var _parseName = function(name) {
|
||||||
|
var rval = [];
|
||||||
|
|
||||||
|
var matches;
|
||||||
|
while(!!(matches = _regex.exec(name))) {
|
||||||
|
if(matches[1].length > 0) {
|
||||||
|
rval.push(matches[1]);
|
||||||
|
}
|
||||||
|
if(matches.length >= 2) {
|
||||||
|
rval.push(matches[2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(rval.length === 0) {
|
||||||
|
rval.push(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rval;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a field from the given form to the given object.
|
||||||
|
*
|
||||||
|
* @param obj the object.
|
||||||
|
* @param names the field as an array of object property names.
|
||||||
|
* @param value the value of the field.
|
||||||
|
* @param dict a dictionary of names to replace.
|
||||||
|
*/
|
||||||
|
var _addField = function(obj, names, value, dict) {
|
||||||
|
// combine array names that fall within square brackets
|
||||||
|
var tmp = [];
|
||||||
|
for(var i = 0; i < names.length; ++i) {
|
||||||
|
// check name for starting square bracket but no ending one
|
||||||
|
var name = names[i];
|
||||||
|
if(name.indexOf('[') !== -1 && name.indexOf(']') === -1 &&
|
||||||
|
i < names.length - 1) {
|
||||||
|
do {
|
||||||
|
name += '.' + names[++i];
|
||||||
|
} while(i < names.length - 1 && names[i].indexOf(']') === -1);
|
||||||
|
}
|
||||||
|
tmp.push(name);
|
||||||
|
}
|
||||||
|
names = tmp;
|
||||||
|
|
||||||
|
// split out array indexes
|
||||||
|
var tmp = [];
|
||||||
|
$.each(names, function(n, name) {
|
||||||
|
tmp = tmp.concat(_parseName(name));
|
||||||
|
});
|
||||||
|
names = tmp;
|
||||||
|
|
||||||
|
// iterate over object property names until value is set
|
||||||
|
$.each(names, function(n, name) {
|
||||||
|
// do dictionary name replacement
|
||||||
|
if(dict && name.length !== 0 && name in dict) {
|
||||||
|
name = dict[name];
|
||||||
|
}
|
||||||
|
|
||||||
|
// blank name indicates appending to an array, set name to
|
||||||
|
// new last index of array
|
||||||
|
if(name.length === 0) {
|
||||||
|
name = obj.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
// value already exists, append value
|
||||||
|
if(obj[name]) {
|
||||||
|
// last name in the field
|
||||||
|
if(n == names.length - 1) {
|
||||||
|
// more than one value, so convert into an array
|
||||||
|
if(!$.isArray(obj[name])) {
|
||||||
|
obj[name] = [obj[name]];
|
||||||
|
}
|
||||||
|
obj[name].push(value);
|
||||||
|
} else {
|
||||||
|
// not last name, go deeper into object
|
||||||
|
obj = obj[name];
|
||||||
|
}
|
||||||
|
} else if(n == names.length - 1) {
|
||||||
|
// new value, last name in the field, set value
|
||||||
|
obj[name] = value;
|
||||||
|
} else {
|
||||||
|
// new value, not last name, go deeper
|
||||||
|
// get next name
|
||||||
|
var next = names[n + 1];
|
||||||
|
|
||||||
|
// blank next value indicates array-appending, so create array
|
||||||
|
if(next.length === 0) {
|
||||||
|
obj[name] = [];
|
||||||
|
} else {
|
||||||
|
// if next name is a number create an array, otherwise a map
|
||||||
|
var isNum = ((next - 0) == next && next.length > 0);
|
||||||
|
obj[name] = isNum ? [] : {};
|
||||||
|
}
|
||||||
|
obj = obj[name];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serializes a form to a JSON object. Object properties will be separated
|
||||||
|
* using the given separator (defaults to '.') and by square brackets.
|
||||||
|
*
|
||||||
|
* @param input the jquery form to serialize.
|
||||||
|
* @param sep the object-property separator (defaults to '.').
|
||||||
|
* @param dict a dictionary of names to replace (name=replace).
|
||||||
|
*
|
||||||
|
* @return the JSON-serialized form.
|
||||||
|
*/
|
||||||
|
form.serialize = function(input, sep, dict) {
|
||||||
|
var rval = {};
|
||||||
|
|
||||||
|
// add all fields in the form to the object
|
||||||
|
sep = sep || '.';
|
||||||
|
$.each(input.serializeArray(), function() {
|
||||||
|
_addField(rval, this.name.split(sep), this.value || '', dict);
|
||||||
|
});
|
||||||
|
|
||||||
|
return rval;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The forge namespace and form API.
|
||||||
|
*/
|
||||||
|
if(typeof forge === 'undefined') {
|
||||||
|
forge = {};
|
||||||
|
}
|
||||||
|
forge.form = form;
|
||||||
|
|
||||||
|
})(jQuery);
|
||||||
200
forge.js/hmac.js
Normal file
@@ -0,0 +1,200 @@
|
|||||||
|
/**
|
||||||
|
* Hash-based Message Authentication Code implementation. Requires a message
|
||||||
|
* digest object that can be obtained, for example, from forge.md.sha1 or
|
||||||
|
* forge.md.md5.
|
||||||
|
*
|
||||||
|
* @author Dave Longley
|
||||||
|
*
|
||||||
|
* Copyright (c) 2010-2012 Digital Bazaar, Inc. All rights reserved.
|
||||||
|
*/
|
||||||
|
(function() {
|
||||||
|
/* ########## Begin module implementation ########## */
|
||||||
|
function initModule(forge) {
|
||||||
|
|
||||||
|
/* HMAC API */
|
||||||
|
var hmac = forge.hmac = forge.hmac || {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an HMAC object that uses the given message digest object.
|
||||||
|
*
|
||||||
|
* @return an HMAC object.
|
||||||
|
*/
|
||||||
|
hmac.create = function() {
|
||||||
|
// the hmac key to use
|
||||||
|
var _key = null;
|
||||||
|
|
||||||
|
// the message digest to use
|
||||||
|
var _md = null;
|
||||||
|
|
||||||
|
// the inner padding
|
||||||
|
var _ipadding = null;
|
||||||
|
|
||||||
|
// the outer padding
|
||||||
|
var _opadding = null;
|
||||||
|
|
||||||
|
// hmac context
|
||||||
|
var ctx = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts or restarts the HMAC with the given key and message digest.
|
||||||
|
*
|
||||||
|
* @param md the message digest to use, null to reuse the previous one,
|
||||||
|
* a string to use builtin 'sha1', 'md5', 'sha256'.
|
||||||
|
* @param key the key to use as a string, array of bytes, byte buffer,
|
||||||
|
* or null to reuse the previous key.
|
||||||
|
*/
|
||||||
|
ctx.start = function(md, key) {
|
||||||
|
if(md !== null) {
|
||||||
|
if(typeof md === 'string') {
|
||||||
|
// create builtin message digest
|
||||||
|
md = md.toLowerCase();
|
||||||
|
if(md in forge.md.algorithms) {
|
||||||
|
_md = forge.md.algorithms[md].create();
|
||||||
|
} else {
|
||||||
|
throw new Error('Unknown hash algorithm "' + md + '"');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// store message digest
|
||||||
|
_md = md;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(key === null) {
|
||||||
|
// reuse previous key
|
||||||
|
key = _key;
|
||||||
|
} else {
|
||||||
|
if(typeof key === 'string') {
|
||||||
|
// convert string into byte buffer
|
||||||
|
key = forge.util.createBuffer(key);
|
||||||
|
} else if(forge.util.isArray(key)) {
|
||||||
|
// convert byte array into byte buffer
|
||||||
|
var tmp = key;
|
||||||
|
key = forge.util.createBuffer();
|
||||||
|
for(var i = 0; i < tmp.length; ++i) {
|
||||||
|
key.putByte(tmp[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if key is longer than blocksize, hash it
|
||||||
|
var keylen = key.length();
|
||||||
|
if(keylen > _md.blockLength) {
|
||||||
|
_md.start();
|
||||||
|
_md.update(key.bytes());
|
||||||
|
key = _md.digest();
|
||||||
|
}
|
||||||
|
|
||||||
|
// mix key into inner and outer padding
|
||||||
|
// ipadding = [0x36 * blocksize] ^ key
|
||||||
|
// opadding = [0x5C * blocksize] ^ key
|
||||||
|
_ipadding = forge.util.createBuffer();
|
||||||
|
_opadding = forge.util.createBuffer();
|
||||||
|
keylen = key.length();
|
||||||
|
for(var i = 0; i < keylen; ++i) {
|
||||||
|
var tmp = key.at(i);
|
||||||
|
_ipadding.putByte(0x36 ^ tmp);
|
||||||
|
_opadding.putByte(0x5C ^ tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
// if key is shorter than blocksize, add additional padding
|
||||||
|
if(keylen < _md.blockLength) {
|
||||||
|
var tmp = _md.blockLength - keylen;
|
||||||
|
for(var i = 0; i < tmp; ++i) {
|
||||||
|
_ipadding.putByte(0x36);
|
||||||
|
_opadding.putByte(0x5C);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_key = key;
|
||||||
|
_ipadding = _ipadding.bytes();
|
||||||
|
_opadding = _opadding.bytes();
|
||||||
|
}
|
||||||
|
|
||||||
|
// digest is done like so: hash(opadding | hash(ipadding | message))
|
||||||
|
|
||||||
|
// prepare to do inner hash
|
||||||
|
// hash(ipadding | message)
|
||||||
|
_md.start();
|
||||||
|
_md.update(_ipadding);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the HMAC with the given message bytes.
|
||||||
|
*
|
||||||
|
* @param bytes the bytes to update with.
|
||||||
|
*/
|
||||||
|
ctx.update = function(bytes) {
|
||||||
|
_md.update(bytes);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Produces the Message Authentication Code (MAC).
|
||||||
|
*
|
||||||
|
* @return a byte buffer containing the digest value.
|
||||||
|
*/
|
||||||
|
ctx.getMac = function() {
|
||||||
|
// digest is done like so: hash(opadding | hash(ipadding | message))
|
||||||
|
// here we do the outer hashing
|
||||||
|
var inner = _md.digest().bytes();
|
||||||
|
_md.start();
|
||||||
|
_md.update(_opadding);
|
||||||
|
_md.update(inner);
|
||||||
|
return _md.digest();
|
||||||
|
};
|
||||||
|
// alias for getMac
|
||||||
|
ctx.digest = ctx.getMac;
|
||||||
|
|
||||||
|
return ctx;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // end module implementation
|
||||||
|
|
||||||
|
/* ########## Begin module wrapper ########## */
|
||||||
|
var name = 'hmac';
|
||||||
|
if(typeof define !== 'function') {
|
||||||
|
// NodeJS -> AMD
|
||||||
|
if(typeof module === 'object' && module.exports) {
|
||||||
|
var nodeJS = true;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
factory(require, module);
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
// <script>
|
||||||
|
if(typeof forge === 'undefined') {
|
||||||
|
forge = {};
|
||||||
|
}
|
||||||
|
return initModule(forge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// AMD
|
||||||
|
var deps;
|
||||||
|
var defineFunc = function(require, module) {
|
||||||
|
module.exports = function(forge) {
|
||||||
|
var mods = deps.map(function(dep) {
|
||||||
|
return require(dep);
|
||||||
|
}).concat(initModule);
|
||||||
|
// handle circular dependencies
|
||||||
|
forge = forge || {};
|
||||||
|
forge.defined = forge.defined || {};
|
||||||
|
if(forge.defined[name]) {
|
||||||
|
return forge[name];
|
||||||
|
}
|
||||||
|
forge.defined[name] = true;
|
||||||
|
for(var i = 0; i < mods.length; ++i) {
|
||||||
|
mods[i](forge);
|
||||||
|
}
|
||||||
|
return forge[name];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
var tmpDefine = define;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
|
||||||
|
if(nodeJS) {
|
||||||
|
delete define;
|
||||||
|
return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
}
|
||||||
|
define = tmpDefine;
|
||||||
|
return define.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
};
|
||||||
|
define(['require', 'module', './md', './util'], function() {
|
||||||
|
defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
});
|
||||||
|
})();
|
||||||
1369
forge.js/http.js
Normal file
1321
forge.js/jsbn.js
Normal file
221
forge.js/kem.js
Normal file
@@ -0,0 +1,221 @@
|
|||||||
|
/**
|
||||||
|
* Javascript implementation of RSA-KEM.
|
||||||
|
*
|
||||||
|
* @author Lautaro Cozzani Rodriguez
|
||||||
|
* @author Dave Longley
|
||||||
|
*
|
||||||
|
* Copyright (c) 2014 Lautaro Cozzani <lautaro.cozzani@scytl.com>
|
||||||
|
* Copyright (c) 2014 Digital Bazaar, Inc.
|
||||||
|
*/
|
||||||
|
(function() {
|
||||||
|
/* ########## Begin module implementation ########## */
|
||||||
|
function initModule(forge) {
|
||||||
|
|
||||||
|
forge.kem = forge.kem || {};
|
||||||
|
|
||||||
|
var BigInteger = forge.jsbn.BigInteger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The API for the RSA Key Encapsulation Mechanism (RSA-KEM) from ISO 18033-2.
|
||||||
|
*/
|
||||||
|
forge.kem.rsa = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an RSA KEM API object for generating a secret asymmetric key.
|
||||||
|
*
|
||||||
|
* The symmetric key may be generated via a call to 'encrypt', which will
|
||||||
|
* produce a ciphertext to be transmitted to the recipient and a key to be
|
||||||
|
* kept secret. The ciphertext is a parameter to be passed to 'decrypt' which
|
||||||
|
* will produce the same secret key for the recipient to use to decrypt a
|
||||||
|
* message that was encrypted with the secret key.
|
||||||
|
*
|
||||||
|
* @param kdf the KDF API to use (eg: new forge.kem.kdf1()).
|
||||||
|
* @param options the options to use.
|
||||||
|
* [prng] a custom crypto-secure pseudo-random number generator to use,
|
||||||
|
* that must define "getBytesSync".
|
||||||
|
*/
|
||||||
|
forge.kem.rsa.create = function(kdf, options) {
|
||||||
|
options = options || {};
|
||||||
|
var prng = options.prng || forge.random;
|
||||||
|
|
||||||
|
var kem = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a secret key and its encapsulation.
|
||||||
|
*
|
||||||
|
* @param publicKey the RSA public key to encrypt with.
|
||||||
|
* @param keyLength the length, in bytes, of the secret key to generate.
|
||||||
|
*
|
||||||
|
* @return an object with:
|
||||||
|
* encapsulation: the ciphertext for generating the secret key, as a
|
||||||
|
* binary-encoded string of bytes.
|
||||||
|
* key: the secret key to use for encrypting a message.
|
||||||
|
*/
|
||||||
|
kem.encrypt = function(publicKey, keyLength) {
|
||||||
|
// generate a random r where 1 > r > n
|
||||||
|
var byteLength = Math.ceil(publicKey.n.bitLength() / 8);
|
||||||
|
var r;
|
||||||
|
do {
|
||||||
|
r = new BigInteger(
|
||||||
|
forge.util.bytesToHex(prng.getBytesSync(byteLength)),
|
||||||
|
16).mod(publicKey.n);
|
||||||
|
} while(r.equals(BigInteger.ZERO));
|
||||||
|
|
||||||
|
// prepend r with zeros
|
||||||
|
r = forge.util.hexToBytes(r.toString(16));
|
||||||
|
var zeros = byteLength - r.length;
|
||||||
|
if(zeros > 0) {
|
||||||
|
r = forge.util.fillString(String.fromCharCode(0), zeros) + r;
|
||||||
|
}
|
||||||
|
|
||||||
|
// encrypt the random
|
||||||
|
var encapsulation = publicKey.encrypt(r, 'NONE');
|
||||||
|
|
||||||
|
// generate the secret key
|
||||||
|
var key = kdf.generate(r, keyLength);
|
||||||
|
|
||||||
|
return {encapsulation: encapsulation, key: key};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decrypts an encapsulated secret key.
|
||||||
|
*
|
||||||
|
* @param privateKey the RSA private key to decrypt with.
|
||||||
|
* @param encapsulation the ciphertext for generating the secret key, as
|
||||||
|
* a binary-encoded string of bytes.
|
||||||
|
* @param keyLength the length, in bytes, of the secret key to generate.
|
||||||
|
*
|
||||||
|
* @return the secret key as a binary-encoded string of bytes.
|
||||||
|
*/
|
||||||
|
kem.decrypt = function(privateKey, encapsulation, keyLength) {
|
||||||
|
// decrypt the encapsulation and generate the secret key
|
||||||
|
var r = privateKey.decrypt(encapsulation, 'NONE');
|
||||||
|
return kdf.generate(r, keyLength);
|
||||||
|
};
|
||||||
|
|
||||||
|
return kem;
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: add forge.kem.kdf.create('KDF1', {md: ..., ...}) API?
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a key derivation API object that implements KDF1 per ISO 18033-2.
|
||||||
|
*
|
||||||
|
* @param md the hash API to use.
|
||||||
|
* @param [digestLength] an optional digest length that must be positive and
|
||||||
|
* less than or equal to md.digestLength.
|
||||||
|
*
|
||||||
|
* @return a KDF1 API object.
|
||||||
|
*/
|
||||||
|
forge.kem.kdf1 = function(md, digestLength) {
|
||||||
|
_createKDF(this, md, 0, digestLength || md.digestLength);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a key derivation API object that implements KDF2 per ISO 18033-2.
|
||||||
|
*
|
||||||
|
* @param md the hash API to use.
|
||||||
|
* @param [digestLength] an optional digest length that must be positive and
|
||||||
|
* less than or equal to md.digestLength.
|
||||||
|
*
|
||||||
|
* @return a KDF2 API object.
|
||||||
|
*/
|
||||||
|
forge.kem.kdf2 = function(md, digestLength) {
|
||||||
|
_createKDF(this, md, 1, digestLength || md.digestLength);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a KDF1 or KDF2 API object.
|
||||||
|
*
|
||||||
|
* @param md the hash API to use.
|
||||||
|
* @param counterStart the starting index for the counter.
|
||||||
|
* @param digestLength the digest length to use.
|
||||||
|
*
|
||||||
|
* @return the KDF API object.
|
||||||
|
*/
|
||||||
|
function _createKDF(kdf, md, counterStart, digestLength) {
|
||||||
|
/**
|
||||||
|
* Generate a key of the specified length.
|
||||||
|
*
|
||||||
|
* @param x the binary-encoded byte string to generate a key from.
|
||||||
|
* @param length the number of bytes to generate (the size of the key).
|
||||||
|
*
|
||||||
|
* @return the key as a binary-encoded string.
|
||||||
|
*/
|
||||||
|
kdf.generate = function(x, length) {
|
||||||
|
var key = new forge.util.ByteBuffer();
|
||||||
|
|
||||||
|
// run counter from counterStart to ceil(length / Hash.len)
|
||||||
|
var k = Math.ceil(length / digestLength) + counterStart;
|
||||||
|
|
||||||
|
var c = new forge.util.ByteBuffer();
|
||||||
|
for(var i = counterStart; i < k; ++i) {
|
||||||
|
// I2OSP(i, 4): convert counter to an octet string of 4 octets
|
||||||
|
c.putInt32(i);
|
||||||
|
|
||||||
|
// digest 'x' and the counter and add the result to the key
|
||||||
|
md.start();
|
||||||
|
md.update(x + c.getBytes());
|
||||||
|
var hash = md.digest();
|
||||||
|
key.putBytes(hash.getBytes(digestLength));
|
||||||
|
}
|
||||||
|
|
||||||
|
// truncate to the correct key length
|
||||||
|
key.truncate(key.length() - length);
|
||||||
|
return key.getBytes();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end module implementation
|
||||||
|
|
||||||
|
/* ########## Begin module wrapper ########## */
|
||||||
|
var name = 'kem';
|
||||||
|
if(typeof define !== 'function') {
|
||||||
|
// NodeJS -> AMD
|
||||||
|
if(typeof module === 'object' && module.exports) {
|
||||||
|
var nodeJS = true;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
factory(require, module);
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
// <script>
|
||||||
|
if(typeof forge === 'undefined') {
|
||||||
|
forge = {};
|
||||||
|
}
|
||||||
|
return initModule(forge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// AMD
|
||||||
|
var deps;
|
||||||
|
var defineFunc = function(require, module) {
|
||||||
|
module.exports = function(forge) {
|
||||||
|
var mods = deps.map(function(dep) {
|
||||||
|
return require(dep);
|
||||||
|
}).concat(initModule);
|
||||||
|
// handle circular dependencies
|
||||||
|
forge = forge || {};
|
||||||
|
forge.defined = forge.defined || {};
|
||||||
|
if(forge.defined[name]) {
|
||||||
|
return forge[name];
|
||||||
|
}
|
||||||
|
forge.defined[name] = true;
|
||||||
|
for(var i = 0; i < mods.length; ++i) {
|
||||||
|
mods[i](forge);
|
||||||
|
}
|
||||||
|
return forge[name];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
var tmpDefine = define;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
|
||||||
|
if(nodeJS) {
|
||||||
|
delete define;
|
||||||
|
return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
}
|
||||||
|
define = tmpDefine;
|
||||||
|
return define.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
};
|
||||||
|
define(['require', 'module', './util','./random','./jsbn'], function() {
|
||||||
|
defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
});
|
||||||
|
})();
|
||||||
372
forge.js/log.js
Normal file
@@ -0,0 +1,372 @@
|
|||||||
|
/**
|
||||||
|
* Cross-browser support for logging in a web application.
|
||||||
|
*
|
||||||
|
* @author David I. Lehn <dlehn@digitalbazaar.com>
|
||||||
|
*
|
||||||
|
* Copyright (c) 2008-2013 Digital Bazaar, Inc.
|
||||||
|
*/
|
||||||
|
(function() {
|
||||||
|
/* ########## Begin module implementation ########## */
|
||||||
|
function initModule(forge) {
|
||||||
|
|
||||||
|
/* LOG API */
|
||||||
|
forge.log = forge.log || {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Application logging system.
|
||||||
|
*
|
||||||
|
* Each logger level available as it's own function of the form:
|
||||||
|
* forge.log.level(category, args...)
|
||||||
|
* The category is an arbitrary string, and the args are the same as
|
||||||
|
* Firebug's console.log API. By default the call will be output as:
|
||||||
|
* 'LEVEL [category] <args[0]>, args[1], ...'
|
||||||
|
* This enables proper % formatting via the first argument.
|
||||||
|
* Each category is enabled by default but can be enabled or disabled with
|
||||||
|
* the setCategoryEnabled() function.
|
||||||
|
*/
|
||||||
|
// list of known levels
|
||||||
|
forge.log.levels = [
|
||||||
|
'none', 'error', 'warning', 'info', 'debug', 'verbose', 'max'];
|
||||||
|
// info on the levels indexed by name:
|
||||||
|
// index: level index
|
||||||
|
// name: uppercased display name
|
||||||
|
var sLevelInfo = {};
|
||||||
|
// list of loggers
|
||||||
|
var sLoggers = [];
|
||||||
|
/**
|
||||||
|
* Standard console logger. If no console support is enabled this will
|
||||||
|
* remain null. Check before using.
|
||||||
|
*/
|
||||||
|
var sConsoleLogger = null;
|
||||||
|
|
||||||
|
// logger flags
|
||||||
|
/**
|
||||||
|
* Lock the level at the current value. Used in cases where user config may
|
||||||
|
* set the level such that only critical messages are seen but more verbose
|
||||||
|
* messages are needed for debugging or other purposes.
|
||||||
|
*/
|
||||||
|
forge.log.LEVEL_LOCKED = (1 << 1);
|
||||||
|
/**
|
||||||
|
* Always call log function. By default, the logging system will check the
|
||||||
|
* message level against logger.level before calling the log function. This
|
||||||
|
* flag allows the function to do its own check.
|
||||||
|
*/
|
||||||
|
forge.log.NO_LEVEL_CHECK = (1 << 2);
|
||||||
|
/**
|
||||||
|
* Perform message interpolation with the passed arguments. "%" style
|
||||||
|
* fields in log messages will be replaced by arguments as needed. Some
|
||||||
|
* loggers, such as Firebug, may do this automatically. The original log
|
||||||
|
* message will be available as 'message' and the interpolated version will
|
||||||
|
* be available as 'fullMessage'.
|
||||||
|
*/
|
||||||
|
forge.log.INTERPOLATE = (1 << 3);
|
||||||
|
|
||||||
|
// setup each log level
|
||||||
|
for(var i = 0; i < forge.log.levels.length; ++i) {
|
||||||
|
var level = forge.log.levels[i];
|
||||||
|
sLevelInfo[level] = {
|
||||||
|
index: i,
|
||||||
|
name: level.toUpperCase()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Message logger. Will dispatch a message to registered loggers as needed.
|
||||||
|
*
|
||||||
|
* @param message message object
|
||||||
|
*/
|
||||||
|
forge.log.logMessage = function(message) {
|
||||||
|
var messageLevelIndex = sLevelInfo[message.level].index;
|
||||||
|
for(var i = 0; i < sLoggers.length; ++i) {
|
||||||
|
var logger = sLoggers[i];
|
||||||
|
if(logger.flags & forge.log.NO_LEVEL_CHECK) {
|
||||||
|
logger.f(message);
|
||||||
|
} else {
|
||||||
|
// get logger level
|
||||||
|
var loggerLevelIndex = sLevelInfo[logger.level].index;
|
||||||
|
// check level
|
||||||
|
if(messageLevelIndex <= loggerLevelIndex) {
|
||||||
|
// message critical enough, call logger
|
||||||
|
logger.f(logger, message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the 'standard' key on a message object to:
|
||||||
|
* "LEVEL [category] " + message
|
||||||
|
*
|
||||||
|
* @param message a message log object
|
||||||
|
*/
|
||||||
|
forge.log.prepareStandard = function(message) {
|
||||||
|
if(!('standard' in message)) {
|
||||||
|
message.standard =
|
||||||
|
sLevelInfo[message.level].name +
|
||||||
|
//' ' + +message.timestamp +
|
||||||
|
' [' + message.category + '] ' +
|
||||||
|
message.message;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the 'full' key on a message object to the original message
|
||||||
|
* interpolated via % formatting with the message arguments.
|
||||||
|
*
|
||||||
|
* @param message a message log object.
|
||||||
|
*/
|
||||||
|
forge.log.prepareFull = function(message) {
|
||||||
|
if(!('full' in message)) {
|
||||||
|
// copy args and insert message at the front
|
||||||
|
var args = [message.message];
|
||||||
|
args = args.concat([] || message['arguments']);
|
||||||
|
// format the message
|
||||||
|
message.full = forge.util.format.apply(this, args);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies both preparseStandard() and prepareFull() to a message object and
|
||||||
|
* store result in 'standardFull'.
|
||||||
|
*
|
||||||
|
* @param message a message log object.
|
||||||
|
*/
|
||||||
|
forge.log.prepareStandardFull = function(message) {
|
||||||
|
if(!('standardFull' in message)) {
|
||||||
|
// FIXME implement 'standardFull' logging
|
||||||
|
forge.log.prepareStandard(message);
|
||||||
|
message.standardFull = message.standard;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// create log level functions
|
||||||
|
if(true) {
|
||||||
|
// levels for which we want functions
|
||||||
|
var levels = ['error', 'warning', 'info', 'debug', 'verbose'];
|
||||||
|
for(var i = 0; i < levels.length; ++i) {
|
||||||
|
// wrap in a function to ensure proper level var is passed
|
||||||
|
(function(level) {
|
||||||
|
// create function for this level
|
||||||
|
forge.log[level] = function(category, message/*, args...*/) {
|
||||||
|
// convert arguments to real array, remove category and message
|
||||||
|
var args = Array.prototype.slice.call(arguments).slice(2);
|
||||||
|
// create message object
|
||||||
|
// Note: interpolation and standard formatting is done lazily
|
||||||
|
var msg = {
|
||||||
|
timestamp: new Date(),
|
||||||
|
level: level,
|
||||||
|
category: category,
|
||||||
|
message: message,
|
||||||
|
'arguments': args
|
||||||
|
/*standard*/
|
||||||
|
/*full*/
|
||||||
|
/*fullMessage*/
|
||||||
|
};
|
||||||
|
// process this message
|
||||||
|
forge.log.logMessage(msg);
|
||||||
|
};
|
||||||
|
})(levels[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new logger with specified custom logging function.
|
||||||
|
*
|
||||||
|
* The logging function has a signature of:
|
||||||
|
* function(logger, message)
|
||||||
|
* logger: current logger
|
||||||
|
* message: object:
|
||||||
|
* level: level id
|
||||||
|
* category: category
|
||||||
|
* message: string message
|
||||||
|
* arguments: Array of extra arguments
|
||||||
|
* fullMessage: interpolated message and arguments if INTERPOLATE flag set
|
||||||
|
*
|
||||||
|
* @param logFunction a logging function which takes a log message object
|
||||||
|
* as a parameter.
|
||||||
|
*
|
||||||
|
* @return a logger object.
|
||||||
|
*/
|
||||||
|
forge.log.makeLogger = function(logFunction) {
|
||||||
|
var logger = {
|
||||||
|
flags: 0,
|
||||||
|
f: logFunction
|
||||||
|
};
|
||||||
|
forge.log.setLevel(logger, 'none');
|
||||||
|
return logger;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the current log level on a logger.
|
||||||
|
*
|
||||||
|
* @param logger the target logger.
|
||||||
|
* @param level the new maximum log level as a string.
|
||||||
|
*
|
||||||
|
* @return true if set, false if not.
|
||||||
|
*/
|
||||||
|
forge.log.setLevel = function(logger, level) {
|
||||||
|
var rval = false;
|
||||||
|
if(logger && !(logger.flags & forge.log.LEVEL_LOCKED)) {
|
||||||
|
for(var i = 0; i < forge.log.levels.length; ++i) {
|
||||||
|
var aValidLevel = forge.log.levels[i];
|
||||||
|
if(level == aValidLevel) {
|
||||||
|
// set level
|
||||||
|
logger.level = level;
|
||||||
|
rval = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rval;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Locks the log level at its current value.
|
||||||
|
*
|
||||||
|
* @param logger the target logger.
|
||||||
|
* @param lock boolean lock value, default to true.
|
||||||
|
*/
|
||||||
|
forge.log.lock = function(logger, lock) {
|
||||||
|
if(typeof lock === 'undefined' || lock) {
|
||||||
|
logger.flags |= forge.log.LEVEL_LOCKED;
|
||||||
|
} else {
|
||||||
|
logger.flags &= ~forge.log.LEVEL_LOCKED;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a logger.
|
||||||
|
*
|
||||||
|
* @param logger the logger object.
|
||||||
|
*/
|
||||||
|
forge.log.addLogger = function(logger) {
|
||||||
|
sLoggers.push(logger);
|
||||||
|
};
|
||||||
|
|
||||||
|
// setup the console logger if possible, else create fake console.log
|
||||||
|
if(typeof(console) !== 'undefined' && 'log' in console) {
|
||||||
|
var logger;
|
||||||
|
if(console.error && console.warn && console.info && console.debug) {
|
||||||
|
// looks like Firebug-style logging is available
|
||||||
|
// level handlers map
|
||||||
|
var levelHandlers = {
|
||||||
|
error: console.error,
|
||||||
|
warning: console.warn,
|
||||||
|
info: console.info,
|
||||||
|
debug: console.debug,
|
||||||
|
verbose: console.debug
|
||||||
|
};
|
||||||
|
var f = function(logger, message) {
|
||||||
|
forge.log.prepareStandard(message);
|
||||||
|
var handler = levelHandlers[message.level];
|
||||||
|
// prepend standard message and concat args
|
||||||
|
var args = [message.standard];
|
||||||
|
args = args.concat(message['arguments'].slice());
|
||||||
|
// apply to low-level console function
|
||||||
|
handler.apply(console, args);
|
||||||
|
};
|
||||||
|
logger = forge.log.makeLogger(f);
|
||||||
|
} else {
|
||||||
|
// only appear to have basic console.log
|
||||||
|
var f = function(logger, message) {
|
||||||
|
forge.log.prepareStandardFull(message);
|
||||||
|
console.log(message.standardFull);
|
||||||
|
};
|
||||||
|
logger = forge.log.makeLogger(f);
|
||||||
|
}
|
||||||
|
forge.log.setLevel(logger, 'debug');
|
||||||
|
forge.log.addLogger(logger);
|
||||||
|
sConsoleLogger = logger;
|
||||||
|
} else {
|
||||||
|
// define fake console.log to avoid potential script errors on
|
||||||
|
// browsers that do not have console logging
|
||||||
|
console = {
|
||||||
|
log: function() {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check for logging control query vars.
|
||||||
|
*
|
||||||
|
* console.level=<level-name>
|
||||||
|
* Set's the console log level by name. Useful to override defaults and
|
||||||
|
* allow more verbose logging before a user config is loaded.
|
||||||
|
*
|
||||||
|
* console.lock=<true|false>
|
||||||
|
* Lock the console log level at whatever level it is set at. This is run
|
||||||
|
* after console.level is processed. Useful to force a level of verbosity
|
||||||
|
* that could otherwise be limited by a user config.
|
||||||
|
*/
|
||||||
|
if(sConsoleLogger !== null) {
|
||||||
|
var query = forge.util.getQueryVariables();
|
||||||
|
if('console.level' in query) {
|
||||||
|
// set with last value
|
||||||
|
forge.log.setLevel(
|
||||||
|
sConsoleLogger, query['console.level'].slice(-1)[0]);
|
||||||
|
}
|
||||||
|
if('console.lock' in query) {
|
||||||
|
// set with last value
|
||||||
|
var lock = query['console.lock'].slice(-1)[0];
|
||||||
|
if(lock == 'true') {
|
||||||
|
forge.log.lock(sConsoleLogger);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// provide public access to console logger
|
||||||
|
forge.log.consoleLogger = sConsoleLogger;
|
||||||
|
|
||||||
|
} // end module implementation
|
||||||
|
|
||||||
|
/* ########## Begin module wrapper ########## */
|
||||||
|
var name = 'log';
|
||||||
|
if(typeof define !== 'function') {
|
||||||
|
// NodeJS -> AMD
|
||||||
|
if(typeof module === 'object' && module.exports) {
|
||||||
|
var nodeJS = true;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
factory(require, module);
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
// <script>
|
||||||
|
if(typeof forge === 'undefined') {
|
||||||
|
forge = {};
|
||||||
|
}
|
||||||
|
return initModule(forge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// AMD
|
||||||
|
var deps;
|
||||||
|
var defineFunc = function(require, module) {
|
||||||
|
module.exports = function(forge) {
|
||||||
|
var mods = deps.map(function(dep) {
|
||||||
|
return require(dep);
|
||||||
|
}).concat(initModule);
|
||||||
|
// handle circular dependencies
|
||||||
|
forge = forge || {};
|
||||||
|
forge.defined = forge.defined || {};
|
||||||
|
if(forge.defined[name]) {
|
||||||
|
return forge[name];
|
||||||
|
}
|
||||||
|
forge.defined[name] = true;
|
||||||
|
for(var i = 0; i < mods.length; ++i) {
|
||||||
|
mods[i](forge);
|
||||||
|
}
|
||||||
|
return forge[name];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
var tmpDefine = define;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
|
||||||
|
if(nodeJS) {
|
||||||
|
delete define;
|
||||||
|
return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
}
|
||||||
|
define = tmpDefine;
|
||||||
|
return define.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
};
|
||||||
|
define(['require', 'module', './util'], function() {
|
||||||
|
defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
});
|
||||||
|
})();
|
||||||
75
forge.js/md.js
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
/**
|
||||||
|
* Node.js module for Forge message digests.
|
||||||
|
*
|
||||||
|
* @author Dave Longley
|
||||||
|
*
|
||||||
|
* Copyright 2011-2014 Digital Bazaar, Inc.
|
||||||
|
*/
|
||||||
|
(function() {
|
||||||
|
/* ########## Begin module implementation ########## */
|
||||||
|
function initModule(forge) {
|
||||||
|
|
||||||
|
forge.md = forge.md || {};
|
||||||
|
forge.md.algorithms = {
|
||||||
|
md5: forge.md5,
|
||||||
|
sha1: forge.sha1,
|
||||||
|
sha256: forge.sha256
|
||||||
|
};
|
||||||
|
forge.md.md5 = forge.md5;
|
||||||
|
forge.md.sha1 = forge.sha1;
|
||||||
|
forge.md.sha256 = forge.sha256;
|
||||||
|
|
||||||
|
} // end module implementation
|
||||||
|
|
||||||
|
/* ########## Begin module wrapper ########## */
|
||||||
|
var name = 'md';
|
||||||
|
if(typeof define !== 'function') {
|
||||||
|
// NodeJS -> AMD
|
||||||
|
if(typeof module === 'object' && module.exports) {
|
||||||
|
var nodeJS = true;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
factory(require, module);
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
// <script>
|
||||||
|
if(typeof forge === 'undefined') {
|
||||||
|
forge = {};
|
||||||
|
}
|
||||||
|
return initModule(forge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// AMD
|
||||||
|
var deps;
|
||||||
|
var defineFunc = function(require, module) {
|
||||||
|
module.exports = function(forge) {
|
||||||
|
var mods = deps.map(function(dep) {
|
||||||
|
return require(dep);
|
||||||
|
}).concat(initModule);
|
||||||
|
// handle circular dependencies
|
||||||
|
forge = forge || {};
|
||||||
|
forge.defined = forge.defined || {};
|
||||||
|
if(forge.defined[name]) {
|
||||||
|
return forge[name];
|
||||||
|
}
|
||||||
|
forge.defined[name] = true;
|
||||||
|
for(var i = 0; i < mods.length; ++i) {
|
||||||
|
mods[i](forge);
|
||||||
|
}
|
||||||
|
return forge[name];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
var tmpDefine = define;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
|
||||||
|
if(nodeJS) {
|
||||||
|
delete define;
|
||||||
|
return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
}
|
||||||
|
define = tmpDefine;
|
||||||
|
return define.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
};
|
||||||
|
define(
|
||||||
|
['require', 'module', './md5', './sha1', './sha256', './sha512'], function() {
|
||||||
|
defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
});
|
||||||
|
})();
|
||||||
345
forge.js/md5.js
Normal file
@@ -0,0 +1,345 @@
|
|||||||
|
/**
|
||||||
|
* Message Digest Algorithm 5 with 128-bit digest (MD5) implementation.
|
||||||
|
*
|
||||||
|
* @author Dave Longley
|
||||||
|
*
|
||||||
|
* Copyright (c) 2010-2014 Digital Bazaar, Inc.
|
||||||
|
*/
|
||||||
|
(function() {
|
||||||
|
/* ########## Begin module implementation ########## */
|
||||||
|
function initModule(forge) {
|
||||||
|
|
||||||
|
var md5 = forge.md5 = forge.md5 || {};
|
||||||
|
forge.md = forge.md || {};
|
||||||
|
forge.md.algorithms = forge.md.algorithms || {};
|
||||||
|
forge.md.md5 = forge.md.algorithms.md5 = md5;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an MD5 message digest object.
|
||||||
|
*
|
||||||
|
* @return a message digest object.
|
||||||
|
*/
|
||||||
|
md5.create = function() {
|
||||||
|
// do initialization as necessary
|
||||||
|
if(!_initialized) {
|
||||||
|
_init();
|
||||||
|
}
|
||||||
|
|
||||||
|
// MD5 state contains four 32-bit integers
|
||||||
|
var _state = null;
|
||||||
|
|
||||||
|
// input buffer
|
||||||
|
var _input = forge.util.createBuffer();
|
||||||
|
|
||||||
|
// used for word storage
|
||||||
|
var _w = new Array(16);
|
||||||
|
|
||||||
|
// message digest object
|
||||||
|
var md = {
|
||||||
|
algorithm: 'md5',
|
||||||
|
blockLength: 64,
|
||||||
|
digestLength: 16,
|
||||||
|
// 56-bit length of message so far (does not including padding)
|
||||||
|
messageLength: 0,
|
||||||
|
// true message length
|
||||||
|
fullMessageLength: null,
|
||||||
|
// size of message length in bytes
|
||||||
|
messageLengthSize: 8
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts the digest.
|
||||||
|
*
|
||||||
|
* @return this digest object.
|
||||||
|
*/
|
||||||
|
md.start = function() {
|
||||||
|
// up to 56-bit message length for convenience
|
||||||
|
md.messageLength = 0;
|
||||||
|
|
||||||
|
// full message length (set md.messageLength64 for backwards-compatibility)
|
||||||
|
md.fullMessageLength = md.messageLength64 = [];
|
||||||
|
var int32s = md.messageLengthSize / 4;
|
||||||
|
for(var i = 0; i < int32s; ++i) {
|
||||||
|
md.fullMessageLength.push(0);
|
||||||
|
}
|
||||||
|
_input = forge.util.createBuffer();
|
||||||
|
_state = {
|
||||||
|
h0: 0x67452301,
|
||||||
|
h1: 0xEFCDAB89,
|
||||||
|
h2: 0x98BADCFE,
|
||||||
|
h3: 0x10325476
|
||||||
|
};
|
||||||
|
return md;
|
||||||
|
};
|
||||||
|
// start digest automatically for first time
|
||||||
|
md.start();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the digest with the given message input. The given input can
|
||||||
|
* treated as raw input (no encoding will be applied) or an encoding of
|
||||||
|
* 'utf8' maybe given to encode the input using UTF-8.
|
||||||
|
*
|
||||||
|
* @param msg the message input to update with.
|
||||||
|
* @param encoding the encoding to use (default: 'raw', other: 'utf8').
|
||||||
|
*
|
||||||
|
* @return this digest object.
|
||||||
|
*/
|
||||||
|
md.update = function(msg, encoding) {
|
||||||
|
if(encoding === 'utf8') {
|
||||||
|
msg = forge.util.encodeUtf8(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
// update message length
|
||||||
|
var len = msg.length;
|
||||||
|
md.messageLength += len;
|
||||||
|
len = [(len / 0x100000000) >>> 0, len >>> 0];
|
||||||
|
for(var i = md.fullMessageLength.length - 1; i >= 0; --i) {
|
||||||
|
md.fullMessageLength[i] += len[1];
|
||||||
|
len[1] = len[0] + ((md.fullMessageLength[i] / 0x100000000) >>> 0);
|
||||||
|
md.fullMessageLength[i] = md.fullMessageLength[i] >>> 0;
|
||||||
|
len[0] = ((len[1] / 0x100000000) >>> 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// add bytes to input buffer
|
||||||
|
_input.putBytes(msg);
|
||||||
|
|
||||||
|
// process bytes
|
||||||
|
_update(_state, _w, _input);
|
||||||
|
|
||||||
|
// compact input buffer every 2K or if empty
|
||||||
|
if(_input.read > 2048 || _input.length() === 0) {
|
||||||
|
_input.compact();
|
||||||
|
}
|
||||||
|
|
||||||
|
return md;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Produces the digest.
|
||||||
|
*
|
||||||
|
* @return a byte buffer containing the digest value.
|
||||||
|
*/
|
||||||
|
md.digest = function() {
|
||||||
|
/* Note: Here we copy the remaining bytes in the input buffer and
|
||||||
|
add the appropriate MD5 padding. Then we do the final update
|
||||||
|
on a copy of the state so that if the user wants to get
|
||||||
|
intermediate digests they can do so. */
|
||||||
|
|
||||||
|
/* Determine the number of bytes that must be added to the message
|
||||||
|
to ensure its length is congruent to 448 mod 512. In other words,
|
||||||
|
the data to be digested must be a multiple of 512 bits (or 128 bytes).
|
||||||
|
This data includes the message, some padding, and the length of the
|
||||||
|
message. Since the length of the message will be encoded as 8 bytes (64
|
||||||
|
bits), that means that the last segment of the data must have 56 bytes
|
||||||
|
(448 bits) of message and padding. Therefore, the length of the message
|
||||||
|
plus the padding must be congruent to 448 mod 512 because
|
||||||
|
512 - 128 = 448.
|
||||||
|
|
||||||
|
In order to fill up the message length it must be filled with
|
||||||
|
padding that begins with 1 bit followed by all 0 bits. Padding
|
||||||
|
must *always* be present, so if the message length is already
|
||||||
|
congruent to 448 mod 512, then 512 padding bits must be added. */
|
||||||
|
|
||||||
|
var finalBlock = forge.util.createBuffer();
|
||||||
|
finalBlock.putBytes(_input.bytes());
|
||||||
|
|
||||||
|
// compute remaining size to be digested (include message length size)
|
||||||
|
var remaining = (
|
||||||
|
md.fullMessageLength[md.fullMessageLength.length - 1] +
|
||||||
|
md.messageLengthSize);
|
||||||
|
|
||||||
|
// add padding for overflow blockSize - overflow
|
||||||
|
// _padding starts with 1 byte with first bit is set (byte value 128), then
|
||||||
|
// there may be up to (blockSize - 1) other pad bytes
|
||||||
|
var overflow = remaining & (md.blockLength - 1);
|
||||||
|
finalBlock.putBytes(_padding.substr(0, md.blockLength - overflow));
|
||||||
|
|
||||||
|
// serialize message length in bits in little-endian order; since length
|
||||||
|
// is stored in bytes we multiply by 8 and add carry
|
||||||
|
var bits, carry = 0;
|
||||||
|
for(var i = md.fullMessageLength.length - 1; i >= 0; --i) {
|
||||||
|
bits = md.fullMessageLength[i] * 8 + carry;
|
||||||
|
carry = (bits / 0x100000000) >>> 0;
|
||||||
|
finalBlock.putInt32Le(bits >>> 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
var s2 = {
|
||||||
|
h0: _state.h0,
|
||||||
|
h1: _state.h1,
|
||||||
|
h2: _state.h2,
|
||||||
|
h3: _state.h3
|
||||||
|
};
|
||||||
|
_update(s2, _w, finalBlock);
|
||||||
|
var rval = forge.util.createBuffer();
|
||||||
|
rval.putInt32Le(s2.h0);
|
||||||
|
rval.putInt32Le(s2.h1);
|
||||||
|
rval.putInt32Le(s2.h2);
|
||||||
|
rval.putInt32Le(s2.h3);
|
||||||
|
return rval;
|
||||||
|
};
|
||||||
|
|
||||||
|
return md;
|
||||||
|
};
|
||||||
|
|
||||||
|
// padding, constant tables for calculating md5
|
||||||
|
var _padding = null;
|
||||||
|
var _g = null;
|
||||||
|
var _r = null;
|
||||||
|
var _k = null;
|
||||||
|
var _initialized = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the constant tables.
|
||||||
|
*/
|
||||||
|
function _init() {
|
||||||
|
// create padding
|
||||||
|
_padding = String.fromCharCode(128);
|
||||||
|
_padding += forge.util.fillString(String.fromCharCode(0x00), 64);
|
||||||
|
|
||||||
|
// g values
|
||||||
|
_g = [
|
||||||
|
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||||
|
1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12,
|
||||||
|
5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2,
|
||||||
|
0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9];
|
||||||
|
|
||||||
|
// rounds table
|
||||||
|
_r = [
|
||||||
|
7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
|
||||||
|
5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,
|
||||||
|
4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
|
||||||
|
6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21];
|
||||||
|
|
||||||
|
// get the result of abs(sin(i + 1)) as a 32-bit integer
|
||||||
|
_k = new Array(64);
|
||||||
|
for(var i = 0; i < 64; ++i) {
|
||||||
|
_k[i] = Math.floor(Math.abs(Math.sin(i + 1)) * 0x100000000);
|
||||||
|
}
|
||||||
|
|
||||||
|
// now initialized
|
||||||
|
_initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates an MD5 state with the given byte buffer.
|
||||||
|
*
|
||||||
|
* @param s the MD5 state to update.
|
||||||
|
* @param w the array to use to store words.
|
||||||
|
* @param bytes the byte buffer to update with.
|
||||||
|
*/
|
||||||
|
function _update(s, w, bytes) {
|
||||||
|
// consume 512 bit (64 byte) chunks
|
||||||
|
var t, a, b, c, d, f, r, i;
|
||||||
|
var len = bytes.length();
|
||||||
|
while(len >= 64) {
|
||||||
|
// initialize hash value for this chunk
|
||||||
|
a = s.h0;
|
||||||
|
b = s.h1;
|
||||||
|
c = s.h2;
|
||||||
|
d = s.h3;
|
||||||
|
|
||||||
|
// round 1
|
||||||
|
for(i = 0; i < 16; ++i) {
|
||||||
|
w[i] = bytes.getInt32Le();
|
||||||
|
f = d ^ (b & (c ^ d));
|
||||||
|
t = (a + f + _k[i] + w[i]);
|
||||||
|
r = _r[i];
|
||||||
|
a = d;
|
||||||
|
d = c;
|
||||||
|
c = b;
|
||||||
|
b += (t << r) | (t >>> (32 - r));
|
||||||
|
}
|
||||||
|
// round 2
|
||||||
|
for(; i < 32; ++i) {
|
||||||
|
f = c ^ (d & (b ^ c));
|
||||||
|
t = (a + f + _k[i] + w[_g[i]]);
|
||||||
|
r = _r[i];
|
||||||
|
a = d;
|
||||||
|
d = c;
|
||||||
|
c = b;
|
||||||
|
b += (t << r) | (t >>> (32 - r));
|
||||||
|
}
|
||||||
|
// round 3
|
||||||
|
for(; i < 48; ++i) {
|
||||||
|
f = b ^ c ^ d;
|
||||||
|
t = (a + f + _k[i] + w[_g[i]]);
|
||||||
|
r = _r[i];
|
||||||
|
a = d;
|
||||||
|
d = c;
|
||||||
|
c = b;
|
||||||
|
b += (t << r) | (t >>> (32 - r));
|
||||||
|
}
|
||||||
|
// round 4
|
||||||
|
for(; i < 64; ++i) {
|
||||||
|
f = c ^ (b | ~d);
|
||||||
|
t = (a + f + _k[i] + w[_g[i]]);
|
||||||
|
r = _r[i];
|
||||||
|
a = d;
|
||||||
|
d = c;
|
||||||
|
c = b;
|
||||||
|
b += (t << r) | (t >>> (32 - r));
|
||||||
|
}
|
||||||
|
|
||||||
|
// update hash state
|
||||||
|
s.h0 = (s.h0 + a) | 0;
|
||||||
|
s.h1 = (s.h1 + b) | 0;
|
||||||
|
s.h2 = (s.h2 + c) | 0;
|
||||||
|
s.h3 = (s.h3 + d) | 0;
|
||||||
|
|
||||||
|
len -= 64;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end module implementation
|
||||||
|
|
||||||
|
/* ########## Begin module wrapper ########## */
|
||||||
|
var name = 'md5';
|
||||||
|
if(typeof define !== 'function') {
|
||||||
|
// NodeJS -> AMD
|
||||||
|
if(typeof module === 'object' && module.exports) {
|
||||||
|
var nodeJS = true;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
factory(require, module);
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
// <script>
|
||||||
|
if(typeof forge === 'undefined') {
|
||||||
|
forge = {};
|
||||||
|
}
|
||||||
|
return initModule(forge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// AMD
|
||||||
|
var deps;
|
||||||
|
var defineFunc = function(require, module) {
|
||||||
|
module.exports = function(forge) {
|
||||||
|
var mods = deps.map(function(dep) {
|
||||||
|
return require(dep);
|
||||||
|
}).concat(initModule);
|
||||||
|
// handle circular dependencies
|
||||||
|
forge = forge || {};
|
||||||
|
forge.defined = forge.defined || {};
|
||||||
|
if(forge.defined[name]) {
|
||||||
|
return forge[name];
|
||||||
|
}
|
||||||
|
forge.defined[name] = true;
|
||||||
|
for(var i = 0; i < mods.length; ++i) {
|
||||||
|
mods[i](forge);
|
||||||
|
}
|
||||||
|
return forge[name];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
var tmpDefine = define;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
|
||||||
|
if(nodeJS) {
|
||||||
|
delete define;
|
||||||
|
return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
}
|
||||||
|
define = tmpDefine;
|
||||||
|
return define.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
};
|
||||||
|
define(['require', 'module', './util'], function() {
|
||||||
|
defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
});
|
||||||
|
})();
|
||||||
67
forge.js/mgf.js
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
/**
|
||||||
|
* Node.js module for Forge mask generation functions.
|
||||||
|
*
|
||||||
|
* @author Stefan Siegl
|
||||||
|
*
|
||||||
|
* Copyright 2012 Stefan Siegl <stesie@brokenpipe.de>
|
||||||
|
*/
|
||||||
|
(function() {
|
||||||
|
/* ########## Begin module implementation ########## */
|
||||||
|
function initModule(forge) {
|
||||||
|
|
||||||
|
forge.mgf = forge.mgf || {};
|
||||||
|
forge.mgf.mgf1 = forge.mgf1;
|
||||||
|
|
||||||
|
} // end module implementation
|
||||||
|
|
||||||
|
/* ########## Begin module wrapper ########## */
|
||||||
|
var name = 'mgf';
|
||||||
|
if(typeof define !== 'function') {
|
||||||
|
// NodeJS -> AMD
|
||||||
|
if(typeof module === 'object' && module.exports) {
|
||||||
|
var nodeJS = true;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
factory(require, module);
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
// <script>
|
||||||
|
if(typeof forge === 'undefined') {
|
||||||
|
forge = {};
|
||||||
|
}
|
||||||
|
return initModule(forge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// AMD
|
||||||
|
var deps;
|
||||||
|
var defineFunc = function(require, module) {
|
||||||
|
module.exports = function(forge) {
|
||||||
|
var mods = deps.map(function(dep) {
|
||||||
|
return require(dep);
|
||||||
|
}).concat(initModule);
|
||||||
|
// handle circular dependencies
|
||||||
|
forge = forge || {};
|
||||||
|
forge.defined = forge.defined || {};
|
||||||
|
if(forge.defined[name]) {
|
||||||
|
return forge[name];
|
||||||
|
}
|
||||||
|
forge.defined[name] = true;
|
||||||
|
for(var i = 0; i < mods.length; ++i) {
|
||||||
|
mods[i](forge);
|
||||||
|
}
|
||||||
|
return forge[name];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
var tmpDefine = define;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
|
||||||
|
if(nodeJS) {
|
||||||
|
delete define;
|
||||||
|
return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
}
|
||||||
|
define = tmpDefine;
|
||||||
|
return define.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
};
|
||||||
|
define(['require', 'module', './mgf1'], function() {
|
||||||
|
defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
});
|
||||||
|
})();
|
||||||
112
forge.js/mgf1.js
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
/**
|
||||||
|
* Javascript implementation of mask generation function MGF1.
|
||||||
|
*
|
||||||
|
* @author Stefan Siegl
|
||||||
|
* @author Dave Longley
|
||||||
|
*
|
||||||
|
* Copyright (c) 2012 Stefan Siegl <stesie@brokenpipe.de>
|
||||||
|
* Copyright (c) 2014 Digital Bazaar, Inc.
|
||||||
|
*/
|
||||||
|
(function() {
|
||||||
|
/* ########## Begin module implementation ########## */
|
||||||
|
function initModule(forge) {
|
||||||
|
|
||||||
|
forge.mgf = forge.mgf || {};
|
||||||
|
var mgf1 = forge.mgf.mgf1 = forge.mgf1 = forge.mgf1 || {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a MGF1 mask generation function object.
|
||||||
|
*
|
||||||
|
* @param md the message digest API to use (eg: forge.md.sha1.create()).
|
||||||
|
*
|
||||||
|
* @return a mask generation function object.
|
||||||
|
*/
|
||||||
|
mgf1.create = function(md) {
|
||||||
|
var mgf = {
|
||||||
|
/**
|
||||||
|
* Generate mask of specified length.
|
||||||
|
*
|
||||||
|
* @param {String} seed The seed for mask generation.
|
||||||
|
* @param maskLen Number of bytes to generate.
|
||||||
|
* @return {String} The generated mask.
|
||||||
|
*/
|
||||||
|
generate: function(seed, maskLen) {
|
||||||
|
/* 2. Let T be the empty octet string. */
|
||||||
|
var t = new forge.util.ByteBuffer();
|
||||||
|
|
||||||
|
/* 3. For counter from 0 to ceil(maskLen / hLen), do the following: */
|
||||||
|
var len = Math.ceil(maskLen / md.digestLength);
|
||||||
|
for(var i = 0; i < len; i++) {
|
||||||
|
/* a. Convert counter to an octet string C of length 4 octets */
|
||||||
|
var c = new forge.util.ByteBuffer();
|
||||||
|
c.putInt32(i);
|
||||||
|
|
||||||
|
/* b. Concatenate the hash of the seed mgfSeed and C to the octet
|
||||||
|
* string T: */
|
||||||
|
md.start();
|
||||||
|
md.update(seed + c.getBytes());
|
||||||
|
t.putBuffer(md.digest());
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Output the leading maskLen octets of T as the octet string mask. */
|
||||||
|
t.truncate(t.length() - maskLen);
|
||||||
|
return t.getBytes();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return mgf;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // end module implementation
|
||||||
|
|
||||||
|
/* ########## Begin module wrapper ########## */
|
||||||
|
var name = 'mgf1';
|
||||||
|
if(typeof define !== 'function') {
|
||||||
|
// NodeJS -> AMD
|
||||||
|
if(typeof module === 'object' && module.exports) {
|
||||||
|
var nodeJS = true;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
factory(require, module);
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
// <script>
|
||||||
|
if(typeof forge === 'undefined') {
|
||||||
|
forge = {};
|
||||||
|
}
|
||||||
|
return initModule(forge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// AMD
|
||||||
|
var deps;
|
||||||
|
var defineFunc = function(require, module) {
|
||||||
|
module.exports = function(forge) {
|
||||||
|
var mods = deps.map(function(dep) {
|
||||||
|
return require(dep);
|
||||||
|
}).concat(initModule);
|
||||||
|
// handle circular dependencies
|
||||||
|
forge = forge || {};
|
||||||
|
forge.defined = forge.defined || {};
|
||||||
|
if(forge.defined[name]) {
|
||||||
|
return forge[name];
|
||||||
|
}
|
||||||
|
forge.defined[name] = true;
|
||||||
|
for(var i = 0; i < mods.length; ++i) {
|
||||||
|
mods[i](forge);
|
||||||
|
}
|
||||||
|
return forge[name];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
var tmpDefine = define;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
|
||||||
|
if(nodeJS) {
|
||||||
|
delete define;
|
||||||
|
return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
}
|
||||||
|
define = tmpDefine;
|
||||||
|
return define.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
};
|
||||||
|
define(['require', 'module', './util'], function() {
|
||||||
|
defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
});
|
||||||
|
})();
|
||||||
269
forge.js/oids.js
Normal file
@@ -0,0 +1,269 @@
|
|||||||
|
/**
|
||||||
|
* Object IDs for ASN.1.
|
||||||
|
*
|
||||||
|
* @author Dave Longley
|
||||||
|
*
|
||||||
|
* Copyright (c) 2010-2013 Digital Bazaar, Inc.
|
||||||
|
*/
|
||||||
|
(function() {
|
||||||
|
/* ########## Begin module implementation ########## */
|
||||||
|
function initModule(forge) {
|
||||||
|
|
||||||
|
forge.pki = forge.pki || {};
|
||||||
|
var oids = forge.pki.oids = forge.oids = forge.oids || {};
|
||||||
|
|
||||||
|
// algorithm OIDs
|
||||||
|
oids['1.2.840.113549.1.1.1'] = 'rsaEncryption';
|
||||||
|
oids['rsaEncryption'] = '1.2.840.113549.1.1.1';
|
||||||
|
// Note: md2 & md4 not implemented
|
||||||
|
//oids['1.2.840.113549.1.1.2'] = 'md2WithRSAEncryption';
|
||||||
|
//oids['md2WithRSAEncryption'] = '1.2.840.113549.1.1.2';
|
||||||
|
//oids['1.2.840.113549.1.1.3'] = 'md4WithRSAEncryption';
|
||||||
|
//oids['md4WithRSAEncryption'] = '1.2.840.113549.1.1.3';
|
||||||
|
oids['1.2.840.113549.1.1.4'] = 'md5WithRSAEncryption';
|
||||||
|
oids['md5WithRSAEncryption'] = '1.2.840.113549.1.1.4';
|
||||||
|
oids['1.2.840.113549.1.1.5'] = 'sha1WithRSAEncryption';
|
||||||
|
oids['sha1WithRSAEncryption'] = '1.2.840.113549.1.1.5';
|
||||||
|
oids['1.2.840.113549.1.1.7'] = 'RSAES-OAEP';
|
||||||
|
oids['RSAES-OAEP'] = '1.2.840.113549.1.1.7';
|
||||||
|
oids['1.2.840.113549.1.1.8'] = 'mgf1';
|
||||||
|
oids['mgf1'] = '1.2.840.113549.1.1.8';
|
||||||
|
oids['1.2.840.113549.1.1.9'] = 'pSpecified';
|
||||||
|
oids['pSpecified'] = '1.2.840.113549.1.1.9';
|
||||||
|
oids['1.2.840.113549.1.1.10'] = 'RSASSA-PSS';
|
||||||
|
oids['RSASSA-PSS'] = '1.2.840.113549.1.1.10';
|
||||||
|
oids['1.2.840.113549.1.1.11'] = 'sha256WithRSAEncryption';
|
||||||
|
oids['sha256WithRSAEncryption'] = '1.2.840.113549.1.1.11';
|
||||||
|
oids['1.2.840.113549.1.1.12'] = 'sha384WithRSAEncryption';
|
||||||
|
oids['sha384WithRSAEncryption'] = '1.2.840.113549.1.1.12';
|
||||||
|
oids['1.2.840.113549.1.1.13'] = 'sha512WithRSAEncryption';
|
||||||
|
oids['sha512WithRSAEncryption'] = '1.2.840.113549.1.1.13';
|
||||||
|
|
||||||
|
oids['1.3.14.3.2.7'] = 'desCBC';
|
||||||
|
oids['desCBC'] = '1.3.14.3.2.7';
|
||||||
|
|
||||||
|
oids['1.3.14.3.2.26'] = 'sha1';
|
||||||
|
oids['sha1'] = '1.3.14.3.2.26';
|
||||||
|
oids['2.16.840.1.101.3.4.2.1'] = 'sha256';
|
||||||
|
oids['sha256'] = '2.16.840.1.101.3.4.2.1';
|
||||||
|
oids['2.16.840.1.101.3.4.2.2'] = 'sha384';
|
||||||
|
oids['sha384'] = '2.16.840.1.101.3.4.2.2';
|
||||||
|
oids['2.16.840.1.101.3.4.2.3'] = 'sha512';
|
||||||
|
oids['sha512'] = '2.16.840.1.101.3.4.2.3';
|
||||||
|
oids['1.2.840.113549.2.5'] = 'md5';
|
||||||
|
oids['md5'] = '1.2.840.113549.2.5';
|
||||||
|
|
||||||
|
// pkcs#7 content types
|
||||||
|
oids['1.2.840.113549.1.7.1'] = 'data';
|
||||||
|
oids['data'] = '1.2.840.113549.1.7.1';
|
||||||
|
oids['1.2.840.113549.1.7.2'] = 'signedData';
|
||||||
|
oids['signedData'] = '1.2.840.113549.1.7.2';
|
||||||
|
oids['1.2.840.113549.1.7.3'] = 'envelopedData';
|
||||||
|
oids['envelopedData'] = '1.2.840.113549.1.7.3';
|
||||||
|
oids['1.2.840.113549.1.7.4'] = 'signedAndEnvelopedData';
|
||||||
|
oids['signedAndEnvelopedData'] = '1.2.840.113549.1.7.4';
|
||||||
|
oids['1.2.840.113549.1.7.5'] = 'digestedData';
|
||||||
|
oids['digestedData'] = '1.2.840.113549.1.7.5';
|
||||||
|
oids['1.2.840.113549.1.7.6'] = 'encryptedData';
|
||||||
|
oids['encryptedData'] = '1.2.840.113549.1.7.6';
|
||||||
|
|
||||||
|
// pkcs#9 oids
|
||||||
|
oids['1.2.840.113549.1.9.1'] = 'emailAddress';
|
||||||
|
oids['emailAddress'] = '1.2.840.113549.1.9.1';
|
||||||
|
oids['1.2.840.113549.1.9.2'] = 'unstructuredName';
|
||||||
|
oids['unstructuredName'] = '1.2.840.113549.1.9.2';
|
||||||
|
oids['1.2.840.113549.1.9.3'] = 'contentType';
|
||||||
|
oids['contentType'] = '1.2.840.113549.1.9.3';
|
||||||
|
oids['1.2.840.113549.1.9.4'] = 'messageDigest';
|
||||||
|
oids['messageDigest'] = '1.2.840.113549.1.9.4';
|
||||||
|
oids['1.2.840.113549.1.9.5'] = 'signingTime';
|
||||||
|
oids['signingTime'] = '1.2.840.113549.1.9.5';
|
||||||
|
oids['1.2.840.113549.1.9.6'] = 'counterSignature';
|
||||||
|
oids['counterSignature'] = '1.2.840.113549.1.9.6';
|
||||||
|
oids['1.2.840.113549.1.9.7'] = 'challengePassword';
|
||||||
|
oids['challengePassword'] = '1.2.840.113549.1.9.7';
|
||||||
|
oids['1.2.840.113549.1.9.8'] = 'unstructuredAddress';
|
||||||
|
oids['unstructuredAddress'] = '1.2.840.113549.1.9.8';
|
||||||
|
oids['1.2.840.113549.1.9.14'] = 'extensionRequest';
|
||||||
|
oids['extensionRequest'] = '1.2.840.113549.1.9.14';
|
||||||
|
|
||||||
|
oids['1.2.840.113549.1.9.20'] = 'friendlyName';
|
||||||
|
oids['friendlyName'] = '1.2.840.113549.1.9.20';
|
||||||
|
oids['1.2.840.113549.1.9.21'] = 'localKeyId';
|
||||||
|
oids['localKeyId'] = '1.2.840.113549.1.9.21';
|
||||||
|
oids['1.2.840.113549.1.9.22.1'] = 'x509Certificate';
|
||||||
|
oids['x509Certificate'] = '1.2.840.113549.1.9.22.1';
|
||||||
|
|
||||||
|
// pkcs#12 safe bags
|
||||||
|
oids['1.2.840.113549.1.12.10.1.1'] = 'keyBag';
|
||||||
|
oids['keyBag'] = '1.2.840.113549.1.12.10.1.1';
|
||||||
|
oids['1.2.840.113549.1.12.10.1.2'] = 'pkcs8ShroudedKeyBag';
|
||||||
|
oids['pkcs8ShroudedKeyBag'] = '1.2.840.113549.1.12.10.1.2';
|
||||||
|
oids['1.2.840.113549.1.12.10.1.3'] = 'certBag';
|
||||||
|
oids['certBag'] = '1.2.840.113549.1.12.10.1.3';
|
||||||
|
oids['1.2.840.113549.1.12.10.1.4'] = 'crlBag';
|
||||||
|
oids['crlBag'] = '1.2.840.113549.1.12.10.1.4';
|
||||||
|
oids['1.2.840.113549.1.12.10.1.5'] = 'secretBag';
|
||||||
|
oids['secretBag'] = '1.2.840.113549.1.12.10.1.5';
|
||||||
|
oids['1.2.840.113549.1.12.10.1.6'] = 'safeContentsBag';
|
||||||
|
oids['safeContentsBag'] = '1.2.840.113549.1.12.10.1.6';
|
||||||
|
|
||||||
|
// password-based-encryption for pkcs#12
|
||||||
|
oids['1.2.840.113549.1.5.13'] = 'pkcs5PBES2';
|
||||||
|
oids['pkcs5PBES2'] = '1.2.840.113549.1.5.13';
|
||||||
|
oids['1.2.840.113549.1.5.12'] = 'pkcs5PBKDF2';
|
||||||
|
oids['pkcs5PBKDF2'] = '1.2.840.113549.1.5.12';
|
||||||
|
|
||||||
|
oids['1.2.840.113549.1.12.1.1'] = 'pbeWithSHAAnd128BitRC4';
|
||||||
|
oids['pbeWithSHAAnd128BitRC4'] = '1.2.840.113549.1.12.1.1';
|
||||||
|
oids['1.2.840.113549.1.12.1.2'] = 'pbeWithSHAAnd40BitRC4';
|
||||||
|
oids['pbeWithSHAAnd40BitRC4'] = '1.2.840.113549.1.12.1.2';
|
||||||
|
oids['1.2.840.113549.1.12.1.3'] = 'pbeWithSHAAnd3-KeyTripleDES-CBC';
|
||||||
|
oids['pbeWithSHAAnd3-KeyTripleDES-CBC'] = '1.2.840.113549.1.12.1.3';
|
||||||
|
oids['1.2.840.113549.1.12.1.4'] = 'pbeWithSHAAnd2-KeyTripleDES-CBC';
|
||||||
|
oids['pbeWithSHAAnd2-KeyTripleDES-CBC'] = '1.2.840.113549.1.12.1.4';
|
||||||
|
oids['1.2.840.113549.1.12.1.5'] = 'pbeWithSHAAnd128BitRC2-CBC';
|
||||||
|
oids['pbeWithSHAAnd128BitRC2-CBC'] = '1.2.840.113549.1.12.1.5';
|
||||||
|
oids['1.2.840.113549.1.12.1.6'] = 'pbewithSHAAnd40BitRC2-CBC';
|
||||||
|
oids['pbewithSHAAnd40BitRC2-CBC'] = '1.2.840.113549.1.12.1.6';
|
||||||
|
|
||||||
|
// symmetric key algorithm oids
|
||||||
|
oids['1.2.840.113549.3.7'] = 'des-EDE3-CBC';
|
||||||
|
oids['des-EDE3-CBC'] = '1.2.840.113549.3.7';
|
||||||
|
oids['2.16.840.1.101.3.4.1.2'] = 'aes128-CBC';
|
||||||
|
oids['aes128-CBC'] = '2.16.840.1.101.3.4.1.2';
|
||||||
|
oids['2.16.840.1.101.3.4.1.22'] = 'aes192-CBC';
|
||||||
|
oids['aes192-CBC'] = '2.16.840.1.101.3.4.1.22';
|
||||||
|
oids['2.16.840.1.101.3.4.1.42'] = 'aes256-CBC';
|
||||||
|
oids['aes256-CBC'] = '2.16.840.1.101.3.4.1.42';
|
||||||
|
|
||||||
|
// certificate issuer/subject OIDs
|
||||||
|
oids['2.5.4.3'] = 'commonName';
|
||||||
|
oids['commonName'] = '2.5.4.3';
|
||||||
|
oids['2.5.4.5'] = 'serialName';
|
||||||
|
oids['serialName'] = '2.5.4.5';
|
||||||
|
oids['2.5.4.6'] = 'countryName';
|
||||||
|
oids['countryName'] = '2.5.4.6';
|
||||||
|
oids['2.5.4.7'] = 'localityName';
|
||||||
|
oids['localityName'] = '2.5.4.7';
|
||||||
|
oids['2.5.4.8'] = 'stateOrProvinceName';
|
||||||
|
oids['stateOrProvinceName'] = '2.5.4.8';
|
||||||
|
oids['2.5.4.10'] = 'organizationName';
|
||||||
|
oids['organizationName'] = '2.5.4.10';
|
||||||
|
oids['2.5.4.11'] = 'organizationalUnitName';
|
||||||
|
oids['organizationalUnitName'] = '2.5.4.11';
|
||||||
|
|
||||||
|
// X.509 extension OIDs
|
||||||
|
oids['2.16.840.1.113730.1.1'] = 'nsCertType';
|
||||||
|
oids['nsCertType'] = '2.16.840.1.113730.1.1';
|
||||||
|
oids['2.5.29.1'] = 'authorityKeyIdentifier'; // deprecated, use .35
|
||||||
|
oids['2.5.29.2'] = 'keyAttributes'; // obsolete use .37 or .15
|
||||||
|
oids['2.5.29.3'] = 'certificatePolicies'; // deprecated, use .32
|
||||||
|
oids['2.5.29.4'] = 'keyUsageRestriction'; // obsolete use .37 or .15
|
||||||
|
oids['2.5.29.5'] = 'policyMapping'; // deprecated use .33
|
||||||
|
oids['2.5.29.6'] = 'subtreesConstraint'; // obsolete use .30
|
||||||
|
oids['2.5.29.7'] = 'subjectAltName'; // deprecated use .17
|
||||||
|
oids['2.5.29.8'] = 'issuerAltName'; // deprecated use .18
|
||||||
|
oids['2.5.29.9'] = 'subjectDirectoryAttributes';
|
||||||
|
oids['2.5.29.10'] = 'basicConstraints'; // deprecated use .19
|
||||||
|
oids['2.5.29.11'] = 'nameConstraints'; // deprecated use .30
|
||||||
|
oids['2.5.29.12'] = 'policyConstraints'; // deprecated use .36
|
||||||
|
oids['2.5.29.13'] = 'basicConstraints'; // deprecated use .19
|
||||||
|
oids['2.5.29.14'] = 'subjectKeyIdentifier';
|
||||||
|
oids['subjectKeyIdentifier'] = '2.5.29.14';
|
||||||
|
oids['2.5.29.15'] = 'keyUsage';
|
||||||
|
oids['keyUsage'] = '2.5.29.15';
|
||||||
|
oids['2.5.29.16'] = 'privateKeyUsagePeriod';
|
||||||
|
oids['2.5.29.17'] = 'subjectAltName';
|
||||||
|
oids['subjectAltName'] = '2.5.29.17';
|
||||||
|
oids['2.5.29.18'] = 'issuerAltName';
|
||||||
|
oids['issuerAltName'] = '2.5.29.18';
|
||||||
|
oids['2.5.29.19'] = 'basicConstraints';
|
||||||
|
oids['basicConstraints'] = '2.5.29.19';
|
||||||
|
oids['2.5.29.20'] = 'cRLNumber';
|
||||||
|
oids['2.5.29.21'] = 'cRLReason';
|
||||||
|
oids['2.5.29.22'] = 'expirationDate';
|
||||||
|
oids['2.5.29.23'] = 'instructionCode';
|
||||||
|
oids['2.5.29.24'] = 'invalidityDate';
|
||||||
|
oids['2.5.29.25'] = 'cRLDistributionPoints'; // deprecated use .31
|
||||||
|
oids['2.5.29.26'] = 'issuingDistributionPoint'; // deprecated use .28
|
||||||
|
oids['2.5.29.27'] = 'deltaCRLIndicator';
|
||||||
|
oids['2.5.29.28'] = 'issuingDistributionPoint';
|
||||||
|
oids['2.5.29.29'] = 'certificateIssuer';
|
||||||
|
oids['2.5.29.30'] = 'nameConstraints';
|
||||||
|
oids['2.5.29.31'] = 'cRLDistributionPoints';
|
||||||
|
oids['2.5.29.32'] = 'certificatePolicies';
|
||||||
|
oids['2.5.29.33'] = 'policyMappings';
|
||||||
|
oids['2.5.29.34'] = 'policyConstraints'; // deprecated use .36
|
||||||
|
oids['2.5.29.35'] = 'authorityKeyIdentifier';
|
||||||
|
oids['2.5.29.36'] = 'policyConstraints';
|
||||||
|
oids['2.5.29.37'] = 'extKeyUsage';
|
||||||
|
oids['extKeyUsage'] = '2.5.29.37';
|
||||||
|
oids['2.5.29.46'] = 'freshestCRL';
|
||||||
|
oids['2.5.29.54'] = 'inhibitAnyPolicy';
|
||||||
|
|
||||||
|
// extKeyUsage purposes
|
||||||
|
oids['1.3.6.1.5.5.7.3.1'] = 'serverAuth';
|
||||||
|
oids['serverAuth'] = '1.3.6.1.5.5.7.3.1';
|
||||||
|
oids['1.3.6.1.5.5.7.3.2'] = 'clientAuth';
|
||||||
|
oids['clientAuth'] = '1.3.6.1.5.5.7.3.2';
|
||||||
|
oids['1.3.6.1.5.5.7.3.3'] = 'codeSigning';
|
||||||
|
oids['codeSigning'] = '1.3.6.1.5.5.7.3.3';
|
||||||
|
oids['1.3.6.1.5.5.7.3.4'] = 'emailProtection';
|
||||||
|
oids['emailProtection'] = '1.3.6.1.5.5.7.3.4';
|
||||||
|
oids['1.3.6.1.5.5.7.3.8'] = 'timeStamping';
|
||||||
|
oids['timeStamping'] = '1.3.6.1.5.5.7.3.8';
|
||||||
|
|
||||||
|
} // end module implementation
|
||||||
|
|
||||||
|
/* ########## Begin module wrapper ########## */
|
||||||
|
var name = 'oids';
|
||||||
|
if(typeof define !== 'function') {
|
||||||
|
// NodeJS -> AMD
|
||||||
|
if(typeof module === 'object' && module.exports) {
|
||||||
|
var nodeJS = true;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
factory(require, module);
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
// <script>
|
||||||
|
if(typeof forge === 'undefined') {
|
||||||
|
forge = {};
|
||||||
|
}
|
||||||
|
return initModule(forge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// AMD
|
||||||
|
var deps;
|
||||||
|
var defineFunc = function(require, module) {
|
||||||
|
module.exports = function(forge) {
|
||||||
|
var mods = deps.map(function(dep) {
|
||||||
|
return require(dep);
|
||||||
|
}).concat(initModule);
|
||||||
|
// handle circular dependencies
|
||||||
|
forge = forge || {};
|
||||||
|
forge.defined = forge.defined || {};
|
||||||
|
if(forge.defined[name]) {
|
||||||
|
return forge[name];
|
||||||
|
}
|
||||||
|
forge.defined[name] = true;
|
||||||
|
for(var i = 0; i < mods.length; ++i) {
|
||||||
|
mods[i](forge);
|
||||||
|
}
|
||||||
|
return forge[name];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
var tmpDefine = define;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
|
||||||
|
if(nodeJS) {
|
||||||
|
delete define;
|
||||||
|
return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
}
|
||||||
|
define = tmpDefine;
|
||||||
|
return define.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
};
|
||||||
|
define(['require', 'module'], function() {
|
||||||
|
defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
});
|
||||||
|
})();
|
||||||
975
forge.js/pbe.js
Normal file
@@ -0,0 +1,975 @@
|
|||||||
|
/**
|
||||||
|
* Password-based encryption functions.
|
||||||
|
*
|
||||||
|
* @author Dave Longley
|
||||||
|
* @author Stefan Siegl <stesie@brokenpipe.de>
|
||||||
|
*
|
||||||
|
* Copyright (c) 2010-2013 Digital Bazaar, Inc.
|
||||||
|
* Copyright (c) 2012 Stefan Siegl <stesie@brokenpipe.de>
|
||||||
|
*
|
||||||
|
* An EncryptedPrivateKeyInfo:
|
||||||
|
*
|
||||||
|
* EncryptedPrivateKeyInfo ::= SEQUENCE {
|
||||||
|
* encryptionAlgorithm EncryptionAlgorithmIdentifier,
|
||||||
|
* encryptedData EncryptedData }
|
||||||
|
*
|
||||||
|
* EncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
|
||||||
|
*
|
||||||
|
* EncryptedData ::= OCTET STRING
|
||||||
|
*/
|
||||||
|
(function() {
|
||||||
|
/* ########## Begin module implementation ########## */
|
||||||
|
function initModule(forge) {
|
||||||
|
|
||||||
|
if(typeof BigInteger === 'undefined') {
|
||||||
|
var BigInteger = forge.jsbn.BigInteger;
|
||||||
|
}
|
||||||
|
|
||||||
|
// shortcut for asn.1 API
|
||||||
|
var asn1 = forge.asn1;
|
||||||
|
|
||||||
|
/* Password-based encryption implementation. */
|
||||||
|
var pki = forge.pki = forge.pki || {};
|
||||||
|
pki.pbe = forge.pbe = forge.pbe || {};
|
||||||
|
var oids = pki.oids;
|
||||||
|
|
||||||
|
// validator for an EncryptedPrivateKeyInfo structure
|
||||||
|
// Note: Currently only works w/algorithm params
|
||||||
|
var encryptedPrivateKeyValidator = {
|
||||||
|
name: 'EncryptedPrivateKeyInfo',
|
||||||
|
tagClass: asn1.Class.UNIVERSAL,
|
||||||
|
type: asn1.Type.SEQUENCE,
|
||||||
|
constructed: true,
|
||||||
|
value: [{
|
||||||
|
name: 'EncryptedPrivateKeyInfo.encryptionAlgorithm',
|
||||||
|
tagClass: asn1.Class.UNIVERSAL,
|
||||||
|
type: asn1.Type.SEQUENCE,
|
||||||
|
constructed: true,
|
||||||
|
value: [{
|
||||||
|
name: 'AlgorithmIdentifier.algorithm',
|
||||||
|
tagClass: asn1.Class.UNIVERSAL,
|
||||||
|
type: asn1.Type.OID,
|
||||||
|
constructed: false,
|
||||||
|
capture: 'encryptionOid'
|
||||||
|
}, {
|
||||||
|
name: 'AlgorithmIdentifier.parameters',
|
||||||
|
tagClass: asn1.Class.UNIVERSAL,
|
||||||
|
type: asn1.Type.SEQUENCE,
|
||||||
|
constructed: true,
|
||||||
|
captureAsn1: 'encryptionParams'
|
||||||
|
}]
|
||||||
|
}, {
|
||||||
|
// encryptedData
|
||||||
|
name: 'EncryptedPrivateKeyInfo.encryptedData',
|
||||||
|
tagClass: asn1.Class.UNIVERSAL,
|
||||||
|
type: asn1.Type.OCTETSTRING,
|
||||||
|
constructed: false,
|
||||||
|
capture: 'encryptedData'
|
||||||
|
}]
|
||||||
|
};
|
||||||
|
|
||||||
|
// validator for a PBES2Algorithms structure
|
||||||
|
// Note: Currently only works w/PBKDF2 + AES encryption schemes
|
||||||
|
var PBES2AlgorithmsValidator = {
|
||||||
|
name: 'PBES2Algorithms',
|
||||||
|
tagClass: asn1.Class.UNIVERSAL,
|
||||||
|
type: asn1.Type.SEQUENCE,
|
||||||
|
constructed: true,
|
||||||
|
value: [{
|
||||||
|
name: 'PBES2Algorithms.keyDerivationFunc',
|
||||||
|
tagClass: asn1.Class.UNIVERSAL,
|
||||||
|
type: asn1.Type.SEQUENCE,
|
||||||
|
constructed: true,
|
||||||
|
value: [{
|
||||||
|
name: 'PBES2Algorithms.keyDerivationFunc.oid',
|
||||||
|
tagClass: asn1.Class.UNIVERSAL,
|
||||||
|
type: asn1.Type.OID,
|
||||||
|
constructed: false,
|
||||||
|
capture: 'kdfOid'
|
||||||
|
}, {
|
||||||
|
name: 'PBES2Algorithms.params',
|
||||||
|
tagClass: asn1.Class.UNIVERSAL,
|
||||||
|
type: asn1.Type.SEQUENCE,
|
||||||
|
constructed: true,
|
||||||
|
value: [{
|
||||||
|
name: 'PBES2Algorithms.params.salt',
|
||||||
|
tagClass: asn1.Class.UNIVERSAL,
|
||||||
|
type: asn1.Type.OCTETSTRING,
|
||||||
|
constructed: false,
|
||||||
|
capture: 'kdfSalt'
|
||||||
|
}, {
|
||||||
|
name: 'PBES2Algorithms.params.iterationCount',
|
||||||
|
tagClass: asn1.Class.UNIVERSAL,
|
||||||
|
type: asn1.Type.INTEGER,
|
||||||
|
onstructed: true,
|
||||||
|
capture: 'kdfIterationCount'
|
||||||
|
}]
|
||||||
|
}]
|
||||||
|
}, {
|
||||||
|
name: 'PBES2Algorithms.encryptionScheme',
|
||||||
|
tagClass: asn1.Class.UNIVERSAL,
|
||||||
|
type: asn1.Type.SEQUENCE,
|
||||||
|
constructed: true,
|
||||||
|
value: [{
|
||||||
|
name: 'PBES2Algorithms.encryptionScheme.oid',
|
||||||
|
tagClass: asn1.Class.UNIVERSAL,
|
||||||
|
type: asn1.Type.OID,
|
||||||
|
constructed: false,
|
||||||
|
capture: 'encOid'
|
||||||
|
}, {
|
||||||
|
name: 'PBES2Algorithms.encryptionScheme.iv',
|
||||||
|
tagClass: asn1.Class.UNIVERSAL,
|
||||||
|
type: asn1.Type.OCTETSTRING,
|
||||||
|
constructed: false,
|
||||||
|
capture: 'encIv'
|
||||||
|
}]
|
||||||
|
}]
|
||||||
|
};
|
||||||
|
|
||||||
|
var pkcs12PbeParamsValidator = {
|
||||||
|
name: 'pkcs-12PbeParams',
|
||||||
|
tagClass: asn1.Class.UNIVERSAL,
|
||||||
|
type: asn1.Type.SEQUENCE,
|
||||||
|
constructed: true,
|
||||||
|
value: [{
|
||||||
|
name: 'pkcs-12PbeParams.salt',
|
||||||
|
tagClass: asn1.Class.UNIVERSAL,
|
||||||
|
type: asn1.Type.OCTETSTRING,
|
||||||
|
constructed: false,
|
||||||
|
capture: 'salt'
|
||||||
|
}, {
|
||||||
|
name: 'pkcs-12PbeParams.iterations',
|
||||||
|
tagClass: asn1.Class.UNIVERSAL,
|
||||||
|
type: asn1.Type.INTEGER,
|
||||||
|
constructed: false,
|
||||||
|
capture: 'iterations'
|
||||||
|
}]
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encrypts a ASN.1 PrivateKeyInfo object, producing an EncryptedPrivateKeyInfo.
|
||||||
|
*
|
||||||
|
* PBES2Algorithms ALGORITHM-IDENTIFIER ::=
|
||||||
|
* { {PBES2-params IDENTIFIED BY id-PBES2}, ...}
|
||||||
|
*
|
||||||
|
* id-PBES2 OBJECT IDENTIFIER ::= {pkcs-5 13}
|
||||||
|
*
|
||||||
|
* PBES2-params ::= SEQUENCE {
|
||||||
|
* keyDerivationFunc AlgorithmIdentifier {{PBES2-KDFs}},
|
||||||
|
* encryptionScheme AlgorithmIdentifier {{PBES2-Encs}}
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* PBES2-KDFs ALGORITHM-IDENTIFIER ::=
|
||||||
|
* { {PBKDF2-params IDENTIFIED BY id-PBKDF2}, ... }
|
||||||
|
*
|
||||||
|
* PBES2-Encs ALGORITHM-IDENTIFIER ::= { ... }
|
||||||
|
*
|
||||||
|
* PBKDF2-params ::= SEQUENCE {
|
||||||
|
* salt CHOICE {
|
||||||
|
* specified OCTET STRING,
|
||||||
|
* otherSource AlgorithmIdentifier {{PBKDF2-SaltSources}}
|
||||||
|
* },
|
||||||
|
* iterationCount INTEGER (1..MAX),
|
||||||
|
* keyLength INTEGER (1..MAX) OPTIONAL,
|
||||||
|
* prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT algid-hmacWithSHA1
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* @param obj the ASN.1 PrivateKeyInfo object.
|
||||||
|
* @param password the password to encrypt with.
|
||||||
|
* @param options:
|
||||||
|
* algorithm the encryption algorithm to use
|
||||||
|
* ('aes128', 'aes192', 'aes256', '3des'), defaults to 'aes128'.
|
||||||
|
* count the iteration count to use.
|
||||||
|
* saltSize the salt size to use.
|
||||||
|
*
|
||||||
|
* @return the ASN.1 EncryptedPrivateKeyInfo.
|
||||||
|
*/
|
||||||
|
pki.encryptPrivateKeyInfo = function(obj, password, options) {
|
||||||
|
// set default options
|
||||||
|
options = options || {};
|
||||||
|
options.saltSize = options.saltSize || 8;
|
||||||
|
options.count = options.count || 2048;
|
||||||
|
options.algorithm = options.algorithm || 'aes128';
|
||||||
|
|
||||||
|
// generate PBE params
|
||||||
|
var salt = forge.random.getBytesSync(options.saltSize);
|
||||||
|
var count = options.count;
|
||||||
|
var countBytes = asn1.integerToDer(count);
|
||||||
|
var dkLen;
|
||||||
|
var encryptionAlgorithm;
|
||||||
|
var encryptedData;
|
||||||
|
if(options.algorithm.indexOf('aes') === 0 || options.algorithm === 'des') {
|
||||||
|
// Do PBES2
|
||||||
|
var ivLen, encOid, cipherFn;
|
||||||
|
switch(options.algorithm) {
|
||||||
|
case 'aes128':
|
||||||
|
dkLen = 16;
|
||||||
|
ivLen = 16;
|
||||||
|
encOid = oids['aes128-CBC'];
|
||||||
|
cipherFn = forge.aes.createEncryptionCipher;
|
||||||
|
break;
|
||||||
|
case 'aes192':
|
||||||
|
dkLen = 24;
|
||||||
|
ivLen = 16;
|
||||||
|
encOid = oids['aes192-CBC'];
|
||||||
|
cipherFn = forge.aes.createEncryptionCipher;
|
||||||
|
break;
|
||||||
|
case 'aes256':
|
||||||
|
dkLen = 32;
|
||||||
|
ivLen = 16;
|
||||||
|
encOid = oids['aes256-CBC'];
|
||||||
|
cipherFn = forge.aes.createEncryptionCipher;
|
||||||
|
break;
|
||||||
|
case 'des':
|
||||||
|
dkLen = 8;
|
||||||
|
ivLen = 8;
|
||||||
|
encOid = oids['desCBC'];
|
||||||
|
cipherFn = forge.des.createEncryptionCipher;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
var error = new Error('Cannot encrypt private key. Unknown encryption algorithm.');
|
||||||
|
error.algorithm = options.algorithm;
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
// encrypt private key using pbe SHA-1 and AES/DES
|
||||||
|
var dk = forge.pkcs5.pbkdf2(password, salt, count, dkLen);
|
||||||
|
var iv = forge.random.getBytesSync(ivLen);
|
||||||
|
var cipher = cipherFn(dk);
|
||||||
|
cipher.start(iv);
|
||||||
|
cipher.update(asn1.toDer(obj));
|
||||||
|
cipher.finish();
|
||||||
|
encryptedData = cipher.output.getBytes();
|
||||||
|
|
||||||
|
encryptionAlgorithm = asn1.create(
|
||||||
|
asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
|
||||||
|
asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false,
|
||||||
|
asn1.oidToDer(oids['pkcs5PBES2']).getBytes()),
|
||||||
|
asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
|
||||||
|
// keyDerivationFunc
|
||||||
|
asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
|
||||||
|
asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false,
|
||||||
|
asn1.oidToDer(oids['pkcs5PBKDF2']).getBytes()),
|
||||||
|
// PBKDF2-params
|
||||||
|
asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
|
||||||
|
// salt
|
||||||
|
asn1.create(
|
||||||
|
asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false, salt),
|
||||||
|
// iteration count
|
||||||
|
asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false,
|
||||||
|
countBytes.getBytes())
|
||||||
|
])
|
||||||
|
]),
|
||||||
|
// encryptionScheme
|
||||||
|
asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
|
||||||
|
asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false,
|
||||||
|
asn1.oidToDer(encOid).getBytes()),
|
||||||
|
// iv
|
||||||
|
asn1.create(
|
||||||
|
asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false, iv)
|
||||||
|
])
|
||||||
|
])
|
||||||
|
]);
|
||||||
|
} else if(options.algorithm === '3des') {
|
||||||
|
// Do PKCS12 PBE
|
||||||
|
dkLen = 24;
|
||||||
|
|
||||||
|
var saltBytes = new forge.util.ByteBuffer(salt);
|
||||||
|
var dk = pki.pbe.generatePkcs12Key(password, saltBytes, 1, count, dkLen);
|
||||||
|
var iv = pki.pbe.generatePkcs12Key(password, saltBytes, 2, count, dkLen);
|
||||||
|
var cipher = forge.des.createEncryptionCipher(dk);
|
||||||
|
cipher.start(iv);
|
||||||
|
cipher.update(asn1.toDer(obj));
|
||||||
|
cipher.finish();
|
||||||
|
encryptedData = cipher.output.getBytes();
|
||||||
|
|
||||||
|
encryptionAlgorithm = asn1.create(
|
||||||
|
asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
|
||||||
|
asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false,
|
||||||
|
asn1.oidToDer(oids['pbeWithSHAAnd3-KeyTripleDES-CBC']).getBytes()),
|
||||||
|
// pkcs-12PbeParams
|
||||||
|
asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
|
||||||
|
// salt
|
||||||
|
asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false, salt),
|
||||||
|
// iteration count
|
||||||
|
asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false,
|
||||||
|
countBytes.getBytes())
|
||||||
|
])
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
var error = new Error('Cannot encrypt private key. Unknown encryption algorithm.');
|
||||||
|
error.algorithm = options.algorithm;
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncryptedPrivateKeyInfo
|
||||||
|
var rval = asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
|
||||||
|
// encryptionAlgorithm
|
||||||
|
encryptionAlgorithm,
|
||||||
|
// encryptedData
|
||||||
|
asn1.create(
|
||||||
|
asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false, encryptedData)
|
||||||
|
]);
|
||||||
|
return rval;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decrypts a ASN.1 PrivateKeyInfo object.
|
||||||
|
*
|
||||||
|
* @param obj the ASN.1 EncryptedPrivateKeyInfo object.
|
||||||
|
* @param password the password to decrypt with.
|
||||||
|
*
|
||||||
|
* @return the ASN.1 PrivateKeyInfo on success, null on failure.
|
||||||
|
*/
|
||||||
|
pki.decryptPrivateKeyInfo = function(obj, password) {
|
||||||
|
var rval = null;
|
||||||
|
|
||||||
|
// get PBE params
|
||||||
|
var capture = {};
|
||||||
|
var errors = [];
|
||||||
|
if(!asn1.validate(obj, encryptedPrivateKeyValidator, capture, errors)) {
|
||||||
|
var error = new Error('Cannot read encrypted private key. ' +
|
||||||
|
'ASN.1 object is not a supported EncryptedPrivateKeyInfo.');
|
||||||
|
error.errors = errors;
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get cipher
|
||||||
|
var oid = asn1.derToOid(capture.encryptionOid);
|
||||||
|
var cipher = pki.pbe.getCipher(oid, capture.encryptionParams, password);
|
||||||
|
|
||||||
|
// get encrypted data
|
||||||
|
var encrypted = forge.util.createBuffer(capture.encryptedData);
|
||||||
|
|
||||||
|
cipher.update(encrypted);
|
||||||
|
if(cipher.finish()) {
|
||||||
|
rval = asn1.fromDer(cipher.output);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rval;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a EncryptedPrivateKeyInfo to PEM format.
|
||||||
|
*
|
||||||
|
* @param epki the EncryptedPrivateKeyInfo.
|
||||||
|
* @param maxline the maximum characters per line, defaults to 64.
|
||||||
|
*
|
||||||
|
* @return the PEM-formatted encrypted private key.
|
||||||
|
*/
|
||||||
|
pki.encryptedPrivateKeyToPem = function(epki, maxline) {
|
||||||
|
// convert to DER, then PEM-encode
|
||||||
|
var msg = {
|
||||||
|
type: 'ENCRYPTED PRIVATE KEY',
|
||||||
|
body: asn1.toDer(epki).getBytes()
|
||||||
|
};
|
||||||
|
return forge.pem.encode(msg, {maxline: maxline});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a PEM-encoded EncryptedPrivateKeyInfo to ASN.1 format. Decryption
|
||||||
|
* is not performed.
|
||||||
|
*
|
||||||
|
* @param pem the EncryptedPrivateKeyInfo in PEM-format.
|
||||||
|
*
|
||||||
|
* @return the ASN.1 EncryptedPrivateKeyInfo.
|
||||||
|
*/
|
||||||
|
pki.encryptedPrivateKeyFromPem = function(pem) {
|
||||||
|
var msg = forge.pem.decode(pem)[0];
|
||||||
|
|
||||||
|
if(msg.type !== 'ENCRYPTED PRIVATE KEY') {
|
||||||
|
var error = new Error('Could not convert encrypted private key from PEM; ' +
|
||||||
|
'PEM header type is "ENCRYPTED PRIVATE KEY".');
|
||||||
|
error.headerType = msg.type;
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
if(msg.procType && msg.procType.type === 'ENCRYPTED') {
|
||||||
|
throw new Error('Could not convert encrypted private key from PEM; ' +
|
||||||
|
'PEM is encrypted.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert DER to ASN.1 object
|
||||||
|
return asn1.fromDer(msg.body);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encrypts an RSA private key. By default, the key will be wrapped in
|
||||||
|
* a PrivateKeyInfo and encrypted to produce a PKCS#8 EncryptedPrivateKeyInfo.
|
||||||
|
* This is the standard, preferred way to encrypt a private key.
|
||||||
|
*
|
||||||
|
* To produce a non-standard PEM-encrypted private key that uses encapsulated
|
||||||
|
* headers to indicate the encryption algorithm (old-style non-PKCS#8 OpenSSL
|
||||||
|
* private key encryption), set the 'legacy' option to true. Note: Using this
|
||||||
|
* option will cause the iteration count to be forced to 1.
|
||||||
|
*
|
||||||
|
* Note: The 'des' algorithm is supported, but it is not considered to be
|
||||||
|
* secure because it only uses a single 56-bit key. If possible, it is highly
|
||||||
|
* recommended that a different algorithm be used.
|
||||||
|
*
|
||||||
|
* @param rsaKey the RSA key to encrypt.
|
||||||
|
* @param password the password to use.
|
||||||
|
* @param options:
|
||||||
|
* algorithm: the encryption algorithm to use
|
||||||
|
* ('aes128', 'aes192', 'aes256', '3des', 'des').
|
||||||
|
* count: the iteration count to use.
|
||||||
|
* saltSize: the salt size to use.
|
||||||
|
* legacy: output an old non-PKCS#8 PEM-encrypted+encapsulated
|
||||||
|
* headers (DEK-Info) private key.
|
||||||
|
*
|
||||||
|
* @return the PEM-encoded ASN.1 EncryptedPrivateKeyInfo.
|
||||||
|
*/
|
||||||
|
pki.encryptRsaPrivateKey = function(rsaKey, password, options) {
|
||||||
|
// standard PKCS#8
|
||||||
|
options = options || {};
|
||||||
|
if(!options.legacy) {
|
||||||
|
// encrypt PrivateKeyInfo
|
||||||
|
var rval = pki.wrapRsaPrivateKey(pki.privateKeyToAsn1(rsaKey));
|
||||||
|
rval = pki.encryptPrivateKeyInfo(rval, password, options);
|
||||||
|
return pki.encryptedPrivateKeyToPem(rval);
|
||||||
|
}
|
||||||
|
|
||||||
|
// legacy non-PKCS#8
|
||||||
|
var algorithm;
|
||||||
|
var iv;
|
||||||
|
var dkLen;
|
||||||
|
var cipherFn;
|
||||||
|
switch(options.algorithm) {
|
||||||
|
case 'aes128':
|
||||||
|
algorithm = 'AES-128-CBC';
|
||||||
|
dkLen = 16;
|
||||||
|
iv = forge.random.getBytesSync(16);
|
||||||
|
cipherFn = forge.aes.createEncryptionCipher;
|
||||||
|
break;
|
||||||
|
case 'aes192':
|
||||||
|
algorithm = 'AES-192-CBC';
|
||||||
|
dkLen = 24;
|
||||||
|
iv = forge.random.getBytesSync(16);
|
||||||
|
cipherFn = forge.aes.createEncryptionCipher;
|
||||||
|
break;
|
||||||
|
case 'aes256':
|
||||||
|
algorithm = 'AES-256-CBC';
|
||||||
|
dkLen = 32;
|
||||||
|
iv = forge.random.getBytesSync(16);
|
||||||
|
cipherFn = forge.aes.createEncryptionCipher;
|
||||||
|
break;
|
||||||
|
case '3des':
|
||||||
|
algorithm = 'DES-EDE3-CBC';
|
||||||
|
dkLen = 24;
|
||||||
|
iv = forge.random.getBytesSync(8);
|
||||||
|
cipherFn = forge.des.createEncryptionCipher;
|
||||||
|
break;
|
||||||
|
case 'des':
|
||||||
|
algorithm = 'DES-CBC';
|
||||||
|
dkLen = 8;
|
||||||
|
iv = forge.random.getBytesSync(8);
|
||||||
|
cipherFn = forge.des.createEncryptionCipher;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
var error = new Error('Could not encrypt RSA private key; unsupported ' +
|
||||||
|
'encryption algorithm "' + options.algorithm + '".');
|
||||||
|
error.algorithm = options.algorithm;
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
// encrypt private key using OpenSSL legacy key derivation
|
||||||
|
var dk = forge.pbe.opensslDeriveBytes(password, iv.substr(0, 8), dkLen);
|
||||||
|
var cipher = cipherFn(dk);
|
||||||
|
cipher.start(iv);
|
||||||
|
cipher.update(asn1.toDer(pki.privateKeyToAsn1(rsaKey)));
|
||||||
|
cipher.finish();
|
||||||
|
|
||||||
|
var msg = {
|
||||||
|
type: 'RSA PRIVATE KEY',
|
||||||
|
procType: {
|
||||||
|
version: '4',
|
||||||
|
type: 'ENCRYPTED'
|
||||||
|
},
|
||||||
|
dekInfo: {
|
||||||
|
algorithm: algorithm,
|
||||||
|
parameters: forge.util.bytesToHex(iv).toUpperCase()
|
||||||
|
},
|
||||||
|
body: cipher.output.getBytes()
|
||||||
|
};
|
||||||
|
return forge.pem.encode(msg);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decrypts an RSA private key.
|
||||||
|
*
|
||||||
|
* @param pem the PEM-formatted EncryptedPrivateKeyInfo to decrypt.
|
||||||
|
* @param password the password to use.
|
||||||
|
*
|
||||||
|
* @return the RSA key on success, null on failure.
|
||||||
|
*/
|
||||||
|
pki.decryptRsaPrivateKey = function(pem, password) {
|
||||||
|
var rval = null;
|
||||||
|
|
||||||
|
var msg = forge.pem.decode(pem)[0];
|
||||||
|
|
||||||
|
if(msg.type !== 'ENCRYPTED PRIVATE KEY' &&
|
||||||
|
msg.type !== 'PRIVATE KEY' &&
|
||||||
|
msg.type !== 'RSA PRIVATE KEY') {
|
||||||
|
var error = new Error('Could not convert private key from PEM; PEM header type ' +
|
||||||
|
'is not "ENCRYPTED PRIVATE KEY", "PRIVATE KEY", or "RSA PRIVATE KEY".');
|
||||||
|
error.headerType = error;
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(msg.procType && msg.procType.type === 'ENCRYPTED') {
|
||||||
|
var dkLen;
|
||||||
|
var cipherFn;
|
||||||
|
switch(msg.dekInfo.algorithm) {
|
||||||
|
case 'DES-CBC':
|
||||||
|
dkLen = 8;
|
||||||
|
cipherFn = forge.des.createDecryptionCipher;
|
||||||
|
break;
|
||||||
|
case 'DES-EDE3-CBC':
|
||||||
|
dkLen = 24;
|
||||||
|
cipherFn = forge.des.createDecryptionCipher;
|
||||||
|
break;
|
||||||
|
case 'AES-128-CBC':
|
||||||
|
dkLen = 16;
|
||||||
|
cipherFn = forge.aes.createDecryptionCipher;
|
||||||
|
break;
|
||||||
|
case 'AES-192-CBC':
|
||||||
|
dkLen = 24;
|
||||||
|
cipherFn = forge.aes.createDecryptionCipher;
|
||||||
|
break;
|
||||||
|
case 'AES-256-CBC':
|
||||||
|
dkLen = 32;
|
||||||
|
cipherFn = forge.aes.createDecryptionCipher;
|
||||||
|
break;
|
||||||
|
case 'RC2-40-CBC':
|
||||||
|
dkLen = 5;
|
||||||
|
cipherFn = function(key) {
|
||||||
|
return forge.rc2.createDecryptionCipher(key, 40);
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
case 'RC2-64-CBC':
|
||||||
|
dkLen = 8;
|
||||||
|
cipherFn = function(key) {
|
||||||
|
return forge.rc2.createDecryptionCipher(key, 64);
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
case 'RC2-128-CBC':
|
||||||
|
dkLen = 16;
|
||||||
|
cipherFn = function(key) {
|
||||||
|
return forge.rc2.createDecryptionCipher(key, 128);
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
var error = new Error('Could not decrypt private key; unsupported ' +
|
||||||
|
'encryption algorithm "' + msg.dekInfo.algorithm + '".');
|
||||||
|
error.algorithm = msg.dekInfo.algorithm;
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
// use OpenSSL legacy key derivation
|
||||||
|
var iv = forge.util.hexToBytes(msg.dekInfo.parameters);
|
||||||
|
var dk = forge.pbe.opensslDeriveBytes(password, iv.substr(0, 8), dkLen);
|
||||||
|
var cipher = cipherFn(dk);
|
||||||
|
cipher.start(iv);
|
||||||
|
cipher.update(forge.util.createBuffer(msg.body));
|
||||||
|
if(cipher.finish()) {
|
||||||
|
rval = cipher.output.getBytes();
|
||||||
|
} else {
|
||||||
|
return rval;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
rval = msg.body;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(msg.type === 'ENCRYPTED PRIVATE KEY') {
|
||||||
|
rval = pki.decryptPrivateKeyInfo(asn1.fromDer(rval), password);
|
||||||
|
} else {
|
||||||
|
// decryption already performed above
|
||||||
|
rval = asn1.fromDer(rval);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(rval !== null) {
|
||||||
|
rval = pki.privateKeyFromAsn1(rval);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rval;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Derives a PKCS#12 key.
|
||||||
|
*
|
||||||
|
* @param password the password to derive the key material from, null or
|
||||||
|
* undefined for none.
|
||||||
|
* @param salt the salt, as a ByteBuffer, to use.
|
||||||
|
* @param id the PKCS#12 ID byte (1 = key material, 2 = IV, 3 = MAC).
|
||||||
|
* @param iter the iteration count.
|
||||||
|
* @param n the number of bytes to derive from the password.
|
||||||
|
* @param md the message digest to use, defaults to SHA-1.
|
||||||
|
*
|
||||||
|
* @return a ByteBuffer with the bytes derived from the password.
|
||||||
|
*/
|
||||||
|
pki.pbe.generatePkcs12Key = function(password, salt, id, iter, n, md) {
|
||||||
|
var j, l;
|
||||||
|
|
||||||
|
if(typeof md === 'undefined' || md === null) {
|
||||||
|
md = forge.md.sha1.create();
|
||||||
|
}
|
||||||
|
|
||||||
|
var u = md.digestLength;
|
||||||
|
var v = md.blockLength;
|
||||||
|
var result = new forge.util.ByteBuffer();
|
||||||
|
|
||||||
|
/* Convert password to Unicode byte buffer + trailing 0-byte. */
|
||||||
|
var passBuf = new forge.util.ByteBuffer();
|
||||||
|
if(password !== null && password !== undefined) {
|
||||||
|
for(l = 0; l < password.length; l++) {
|
||||||
|
passBuf.putInt16(password.charCodeAt(l));
|
||||||
|
}
|
||||||
|
passBuf.putInt16(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Length of salt and password in BYTES. */
|
||||||
|
var p = passBuf.length();
|
||||||
|
var s = salt.length();
|
||||||
|
|
||||||
|
/* 1. Construct a string, D (the "diversifier"), by concatenating
|
||||||
|
v copies of ID. */
|
||||||
|
var D = new forge.util.ByteBuffer();
|
||||||
|
D.fillWithByte(id, v);
|
||||||
|
|
||||||
|
/* 2. Concatenate copies of the salt together to create a string S of length
|
||||||
|
v * ceil(s / v) bytes (the final copy of the salt may be trunacted
|
||||||
|
to create S).
|
||||||
|
Note that if the salt is the empty string, then so is S. */
|
||||||
|
var Slen = v * Math.ceil(s / v);
|
||||||
|
var S = new forge.util.ByteBuffer();
|
||||||
|
for(l = 0; l < Slen; l ++) {
|
||||||
|
S.putByte(salt.at(l % s));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 3. Concatenate copies of the password together to create a string P of
|
||||||
|
length v * ceil(p / v) bytes (the final copy of the password may be
|
||||||
|
truncated to create P).
|
||||||
|
Note that if the password is the empty string, then so is P. */
|
||||||
|
var Plen = v * Math.ceil(p / v);
|
||||||
|
var P = new forge.util.ByteBuffer();
|
||||||
|
for(l = 0; l < Plen; l ++) {
|
||||||
|
P.putByte(passBuf.at(l % p));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 4. Set I=S||P to be the concatenation of S and P. */
|
||||||
|
var I = S;
|
||||||
|
I.putBuffer(P);
|
||||||
|
|
||||||
|
/* 5. Set c=ceil(n / u). */
|
||||||
|
var c = Math.ceil(n / u);
|
||||||
|
|
||||||
|
/* 6. For i=1, 2, ..., c, do the following: */
|
||||||
|
for(var i = 1; i <= c; i ++) {
|
||||||
|
/* a) Set Ai=H^r(D||I). (l.e. the rth hash of D||I, H(H(H(...H(D||I)))) */
|
||||||
|
var buf = new forge.util.ByteBuffer();
|
||||||
|
buf.putBytes(D.bytes());
|
||||||
|
buf.putBytes(I.bytes());
|
||||||
|
for(var round = 0; round < iter; round ++) {
|
||||||
|
md.start();
|
||||||
|
md.update(buf.getBytes());
|
||||||
|
buf = md.digest();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* b) Concatenate copies of Ai to create a string B of length v bytes (the
|
||||||
|
final copy of Ai may be truncated to create B). */
|
||||||
|
var B = new forge.util.ByteBuffer();
|
||||||
|
for(l = 0; l < v; l ++) {
|
||||||
|
B.putByte(buf.at(l % u));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* c) Treating I as a concatenation I0, I1, ..., Ik-1 of v-byte blocks,
|
||||||
|
where k=ceil(s / v) + ceil(p / v), modify I by setting
|
||||||
|
Ij=(Ij+B+1) mod 2v for each j. */
|
||||||
|
var k = Math.ceil(s / v) + Math.ceil(p / v);
|
||||||
|
var Inew = new forge.util.ByteBuffer();
|
||||||
|
for(j = 0; j < k; j ++) {
|
||||||
|
var chunk = new forge.util.ByteBuffer(I.getBytes(v));
|
||||||
|
var x = 0x1ff;
|
||||||
|
for(l = B.length() - 1; l >= 0; l --) {
|
||||||
|
x = x >> 8;
|
||||||
|
x += B.at(l) + chunk.at(l);
|
||||||
|
chunk.setAt(l, x & 0xff);
|
||||||
|
}
|
||||||
|
Inew.putBuffer(chunk);
|
||||||
|
}
|
||||||
|
I = Inew;
|
||||||
|
|
||||||
|
/* Add Ai to A. */
|
||||||
|
result.putBuffer(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
result.truncate(result.length() - n);
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get new Forge cipher object instance.
|
||||||
|
*
|
||||||
|
* @param oid the OID (in string notation).
|
||||||
|
* @param params the ASN.1 params object.
|
||||||
|
* @param password the password to decrypt with.
|
||||||
|
*
|
||||||
|
* @return new cipher object instance.
|
||||||
|
*/
|
||||||
|
pki.pbe.getCipher = function(oid, params, password) {
|
||||||
|
switch(oid) {
|
||||||
|
case pki.oids['pkcs5PBES2']:
|
||||||
|
return pki.pbe.getCipherForPBES2(oid, params, password);
|
||||||
|
|
||||||
|
case pki.oids['pbeWithSHAAnd3-KeyTripleDES-CBC']:
|
||||||
|
case pki.oids['pbewithSHAAnd40BitRC2-CBC']:
|
||||||
|
return pki.pbe.getCipherForPKCS12PBE(oid, params, password);
|
||||||
|
|
||||||
|
default:
|
||||||
|
var error = new Error('Cannot read encrypted PBE data block. Unsupported OID.');
|
||||||
|
error.oid = oid;
|
||||||
|
error.supportedOids = [
|
||||||
|
'pkcs5PBES2',
|
||||||
|
'pbeWithSHAAnd3-KeyTripleDES-CBC',
|
||||||
|
'pbewithSHAAnd40BitRC2-CBC'
|
||||||
|
];
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get new Forge cipher object instance according to PBES2 params block.
|
||||||
|
*
|
||||||
|
* The returned cipher instance is already started using the IV
|
||||||
|
* from PBES2 parameter block.
|
||||||
|
*
|
||||||
|
* @param oid the PKCS#5 PBKDF2 OID (in string notation).
|
||||||
|
* @param params the ASN.1 PBES2-params object.
|
||||||
|
* @param password the password to decrypt with.
|
||||||
|
*
|
||||||
|
* @return new cipher object instance.
|
||||||
|
*/
|
||||||
|
pki.pbe.getCipherForPBES2 = function(oid, params, password) {
|
||||||
|
// get PBE params
|
||||||
|
var capture = {};
|
||||||
|
var errors = [];
|
||||||
|
if(!asn1.validate(params, PBES2AlgorithmsValidator, capture, errors)) {
|
||||||
|
var error = new Error('Cannot read password-based-encryption algorithm ' +
|
||||||
|
'parameters. ASN.1 object is not a supported EncryptedPrivateKeyInfo.');
|
||||||
|
error.errors = errors;
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check oids
|
||||||
|
oid = asn1.derToOid(capture.kdfOid);
|
||||||
|
if(oid !== pki.oids['pkcs5PBKDF2']) {
|
||||||
|
var error = new Error('Cannot read encrypted private key. ' +
|
||||||
|
'Unsupported key derivation function OID.');
|
||||||
|
error.oid = oid;
|
||||||
|
error.supportedOids = ['pkcs5PBKDF2'];
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
oid = asn1.derToOid(capture.encOid);
|
||||||
|
if(oid !== pki.oids['aes128-CBC'] &&
|
||||||
|
oid !== pki.oids['aes192-CBC'] &&
|
||||||
|
oid !== pki.oids['aes256-CBC'] &&
|
||||||
|
oid !== pki.oids['des-EDE3-CBC'] &&
|
||||||
|
oid !== pki.oids['desCBC']) {
|
||||||
|
var error = new Error('Cannot read encrypted private key. ' +
|
||||||
|
'Unsupported encryption scheme OID.');
|
||||||
|
error.oid = oid;
|
||||||
|
error.supportedOids = [
|
||||||
|
'aes128-CBC', 'aes192-CBC', 'aes256-CBC', 'des-EDE3-CBC', 'desCBC'];
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set PBE params
|
||||||
|
var salt = capture.kdfSalt;
|
||||||
|
var count = forge.util.createBuffer(capture.kdfIterationCount);
|
||||||
|
count = count.getInt(count.length() << 3);
|
||||||
|
var dkLen;
|
||||||
|
var cipherFn;
|
||||||
|
switch(pki.oids[oid]) {
|
||||||
|
case 'aes128-CBC':
|
||||||
|
dkLen = 16;
|
||||||
|
cipherFn = forge.aes.createDecryptionCipher;
|
||||||
|
break;
|
||||||
|
case 'aes192-CBC':
|
||||||
|
dkLen = 24;
|
||||||
|
cipherFn = forge.aes.createDecryptionCipher;
|
||||||
|
break;
|
||||||
|
case 'aes256-CBC':
|
||||||
|
dkLen = 32;
|
||||||
|
cipherFn = forge.aes.createDecryptionCipher;
|
||||||
|
break;
|
||||||
|
case 'des-EDE3-CBC':
|
||||||
|
dkLen = 24;
|
||||||
|
cipherFn = forge.des.createDecryptionCipher;
|
||||||
|
break;
|
||||||
|
case 'desCBC':
|
||||||
|
dkLen = 8;
|
||||||
|
cipherFn = forge.des.createDecryptionCipher;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// decrypt private key using pbe SHA-1 and AES/DES
|
||||||
|
var dk = forge.pkcs5.pbkdf2(password, salt, count, dkLen);
|
||||||
|
var iv = capture.encIv;
|
||||||
|
var cipher = cipherFn(dk);
|
||||||
|
cipher.start(iv);
|
||||||
|
|
||||||
|
return cipher;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get new Forge cipher object instance for PKCS#12 PBE.
|
||||||
|
*
|
||||||
|
* The returned cipher instance is already started using the key & IV
|
||||||
|
* derived from the provided password and PKCS#12 PBE salt.
|
||||||
|
*
|
||||||
|
* @param oid The PKCS#12 PBE OID (in string notation).
|
||||||
|
* @param params The ASN.1 PKCS#12 PBE-params object.
|
||||||
|
* @param password The password to decrypt with.
|
||||||
|
*
|
||||||
|
* @return the new cipher object instance.
|
||||||
|
*/
|
||||||
|
pki.pbe.getCipherForPKCS12PBE = function(oid, params, password) {
|
||||||
|
// get PBE params
|
||||||
|
var capture = {};
|
||||||
|
var errors = [];
|
||||||
|
if(!asn1.validate(params, pkcs12PbeParamsValidator, capture, errors)) {
|
||||||
|
var error = new Error('Cannot read password-based-encryption algorithm ' +
|
||||||
|
'parameters. ASN.1 object is not a supported EncryptedPrivateKeyInfo.');
|
||||||
|
error.errors = errors;
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
var salt = forge.util.createBuffer(capture.salt);
|
||||||
|
var count = forge.util.createBuffer(capture.iterations);
|
||||||
|
count = count.getInt(count.length() << 3);
|
||||||
|
|
||||||
|
var dkLen, dIvLen, cipherFn;
|
||||||
|
switch(oid) {
|
||||||
|
case pki.oids['pbeWithSHAAnd3-KeyTripleDES-CBC']:
|
||||||
|
dkLen = 24;
|
||||||
|
dIvLen = 8;
|
||||||
|
cipherFn = forge.des.startDecrypting;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case pki.oids['pbewithSHAAnd40BitRC2-CBC']:
|
||||||
|
dkLen = 5;
|
||||||
|
dIvLen = 8;
|
||||||
|
cipherFn = function(key, iv) {
|
||||||
|
var cipher = forge.rc2.createDecryptionCipher(key, 40);
|
||||||
|
cipher.start(iv, null);
|
||||||
|
return cipher;
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
var error = new Error('Cannot read PKCS #12 PBE data block. Unsupported OID.');
|
||||||
|
error.oid = oid;
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
var key = pki.pbe.generatePkcs12Key(password, salt, 1, count, dkLen);
|
||||||
|
var iv = pki.pbe.generatePkcs12Key(password, salt, 2, count, dIvLen);
|
||||||
|
|
||||||
|
return cipherFn(key, iv);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OpenSSL's legacy key derivation function.
|
||||||
|
*
|
||||||
|
* See: http://www.openssl.org/docs/crypto/EVP_BytesToKey.html
|
||||||
|
*
|
||||||
|
* @param password the password to derive the key from.
|
||||||
|
* @param salt the salt to use, null for none.
|
||||||
|
* @param dkLen the number of bytes needed for the derived key.
|
||||||
|
* @param [options] the options to use:
|
||||||
|
* [md] an optional message digest object to use.
|
||||||
|
*/
|
||||||
|
pki.pbe.opensslDeriveBytes = function(password, salt, dkLen, md) {
|
||||||
|
if(typeof md === 'undefined' || md === null) {
|
||||||
|
md = forge.md.md5.create();
|
||||||
|
}
|
||||||
|
if(salt === null) {
|
||||||
|
salt = '';
|
||||||
|
}
|
||||||
|
var digests = [hash(md, password + salt)];
|
||||||
|
for(var length = 16, i = 1; length < dkLen; ++i, length += 16) {
|
||||||
|
digests.push(hash(md, digests[i - 1] + password + salt));
|
||||||
|
}
|
||||||
|
return digests.join('').substr(0, dkLen);
|
||||||
|
};
|
||||||
|
|
||||||
|
function hash(md, bytes) {
|
||||||
|
return md.start().update(bytes).digest().getBytes();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end module implementation
|
||||||
|
|
||||||
|
/* ########## Begin module wrapper ########## */
|
||||||
|
var name = 'pbe';
|
||||||
|
if(typeof define !== 'function') {
|
||||||
|
// NodeJS -> AMD
|
||||||
|
if(typeof module === 'object' && module.exports) {
|
||||||
|
var nodeJS = true;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
factory(require, module);
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
// <script>
|
||||||
|
if(typeof forge === 'undefined') {
|
||||||
|
forge = {};
|
||||||
|
}
|
||||||
|
return initModule(forge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// AMD
|
||||||
|
var deps;
|
||||||
|
var defineFunc = function(require, module) {
|
||||||
|
module.exports = function(forge) {
|
||||||
|
var mods = deps.map(function(dep) {
|
||||||
|
return require(dep);
|
||||||
|
}).concat(initModule);
|
||||||
|
// handle circular dependencies
|
||||||
|
forge = forge || {};
|
||||||
|
forge.defined = forge.defined || {};
|
||||||
|
if(forge.defined[name]) {
|
||||||
|
return forge[name];
|
||||||
|
}
|
||||||
|
forge.defined[name] = true;
|
||||||
|
for(var i = 0; i < mods.length; ++i) {
|
||||||
|
mods[i](forge);
|
||||||
|
}
|
||||||
|
return forge[name];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
var tmpDefine = define;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
|
||||||
|
if(nodeJS) {
|
||||||
|
delete define;
|
||||||
|
return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
}
|
||||||
|
define = tmpDefine;
|
||||||
|
return define.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
};
|
||||||
|
define([
|
||||||
|
'require',
|
||||||
|
'module',
|
||||||
|
'./aes',
|
||||||
|
'./asn1',
|
||||||
|
'./des',
|
||||||
|
'./md',
|
||||||
|
'./oids',
|
||||||
|
'./pem',
|
||||||
|
'./pbkdf2',
|
||||||
|
'./random',
|
||||||
|
'./rc2',
|
||||||
|
'./rsa',
|
||||||
|
'./util'
|
||||||
|
], function() {
|
||||||
|
defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
});
|
||||||
|
})();
|
||||||
264
forge.js/pbkdf2.js
Normal file
@@ -0,0 +1,264 @@
|
|||||||
|
/**
|
||||||
|
* Password-Based Key-Derivation Function #2 implementation.
|
||||||
|
*
|
||||||
|
* See RFC 2898 for details.
|
||||||
|
*
|
||||||
|
* @author Dave Longley
|
||||||
|
*
|
||||||
|
* Copyright (c) 2010-2013 Digital Bazaar, Inc.
|
||||||
|
*/
|
||||||
|
(function() {
|
||||||
|
/* ########## Begin module implementation ########## */
|
||||||
|
function initModule(forge) {
|
||||||
|
|
||||||
|
var pkcs5 = forge.pkcs5 = forge.pkcs5 || {};
|
||||||
|
|
||||||
|
var _nodejs = (
|
||||||
|
typeof process !== 'undefined' && process.versions && process.versions.node);
|
||||||
|
var crypto;
|
||||||
|
if(_nodejs && !forge.disableNativeCode) {
|
||||||
|
crypto = require('crypto');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Derives a key from a password.
|
||||||
|
*
|
||||||
|
* @param p the password as a binary-encoded string of bytes.
|
||||||
|
* @param s the salt as a binary-encoded string of bytes.
|
||||||
|
* @param c the iteration count, a positive integer.
|
||||||
|
* @param dkLen the intended length, in bytes, of the derived key,
|
||||||
|
* (max: 2^32 - 1) * hash length of the PRF.
|
||||||
|
* @param [md] the message digest (or algorithm identifier as a string) to use
|
||||||
|
* in the PRF, defaults to SHA-1.
|
||||||
|
* @param [callback(err, key)] presence triggers asynchronous version, called
|
||||||
|
* once the operation completes.
|
||||||
|
*
|
||||||
|
* @return the derived key, as a binary-encoded string of bytes, for the
|
||||||
|
* synchronous version (if no callback is specified).
|
||||||
|
*/
|
||||||
|
forge.pbkdf2 = pkcs5.pbkdf2 = function(p, s, c, dkLen, md, callback) {
|
||||||
|
if(typeof md === 'function') {
|
||||||
|
callback = md;
|
||||||
|
md = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// use native implementation if possible and not disabled, note that
|
||||||
|
// some node versions only support SHA-1, others allow digest to be changed
|
||||||
|
if(_nodejs && !forge.disableNativeCode && crypto.pbkdf2 &&
|
||||||
|
(md === null || typeof md !== 'object') &&
|
||||||
|
(crypto.pbkdf2Sync.length > 4 || (!md || md === 'sha1'))) {
|
||||||
|
if(typeof md !== 'string') {
|
||||||
|
// default prf to SHA-1
|
||||||
|
md = 'sha1';
|
||||||
|
}
|
||||||
|
s = new Buffer(s, 'binary');
|
||||||
|
if(!callback) {
|
||||||
|
if(crypto.pbkdf2Sync.length === 4) {
|
||||||
|
return crypto.pbkdf2Sync(p, s, c, dkLen).toString('binary');
|
||||||
|
}
|
||||||
|
return crypto.pbkdf2Sync(p, s, c, dkLen, md).toString('binary');
|
||||||
|
}
|
||||||
|
if(crypto.pbkdf2Sync.length === 4) {
|
||||||
|
return crypto.pbkdf2(p, s, c, dkLen, function(err, key) {
|
||||||
|
if(err) {
|
||||||
|
return callback(err);
|
||||||
|
}
|
||||||
|
callback(null, key.toString('binary'));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return crypto.pbkdf2(p, s, c, dkLen, md, function(err, key) {
|
||||||
|
if(err) {
|
||||||
|
return callback(err);
|
||||||
|
}
|
||||||
|
callback(null, key.toString('binary'));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if(typeof md === 'undefined' || md === null) {
|
||||||
|
// default prf to SHA-1
|
||||||
|
md = forge.md.sha1.create();
|
||||||
|
}
|
||||||
|
if(typeof md === 'string') {
|
||||||
|
if(!(md in forge.md.algorithms)) {
|
||||||
|
throw new Error('Unknown hash algorithm: ' + md);
|
||||||
|
}
|
||||||
|
md = forge.md[md].create();
|
||||||
|
}
|
||||||
|
|
||||||
|
var hLen = md.digestLength;
|
||||||
|
|
||||||
|
/* 1. If dkLen > (2^32 - 1) * hLen, output "derived key too long" and
|
||||||
|
stop. */
|
||||||
|
if(dkLen > (0xFFFFFFFF * hLen)) {
|
||||||
|
var err = new Error('Derived key is too long.');
|
||||||
|
if(callback) {
|
||||||
|
return callback(err);
|
||||||
|
}
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 2. Let len be the number of hLen-octet blocks in the derived key,
|
||||||
|
rounding up, and let r be the number of octets in the last
|
||||||
|
block:
|
||||||
|
|
||||||
|
len = CEIL(dkLen / hLen),
|
||||||
|
r = dkLen - (len - 1) * hLen. */
|
||||||
|
var len = Math.ceil(dkLen / hLen);
|
||||||
|
var r = dkLen - (len - 1) * hLen;
|
||||||
|
|
||||||
|
/* 3. For each block of the derived key apply the function F defined
|
||||||
|
below to the password P, the salt S, the iteration count c, and
|
||||||
|
the block index to compute the block:
|
||||||
|
|
||||||
|
T_1 = F(P, S, c, 1),
|
||||||
|
T_2 = F(P, S, c, 2),
|
||||||
|
...
|
||||||
|
T_len = F(P, S, c, len),
|
||||||
|
|
||||||
|
where the function F is defined as the exclusive-or sum of the
|
||||||
|
first c iterates of the underlying pseudorandom function PRF
|
||||||
|
applied to the password P and the concatenation of the salt S
|
||||||
|
and the block index i:
|
||||||
|
|
||||||
|
F(P, S, c, i) = u_1 XOR u_2 XOR ... XOR u_c
|
||||||
|
|
||||||
|
where
|
||||||
|
|
||||||
|
u_1 = PRF(P, S || INT(i)),
|
||||||
|
u_2 = PRF(P, u_1),
|
||||||
|
...
|
||||||
|
u_c = PRF(P, u_{c-1}).
|
||||||
|
|
||||||
|
Here, INT(i) is a four-octet encoding of the integer i, most
|
||||||
|
significant octet first. */
|
||||||
|
var prf = forge.hmac.create();
|
||||||
|
prf.start(md, p);
|
||||||
|
var dk = '';
|
||||||
|
var xor, u_c, u_c1;
|
||||||
|
|
||||||
|
// sync version
|
||||||
|
if(!callback) {
|
||||||
|
for(var i = 1; i <= len; ++i) {
|
||||||
|
// PRF(P, S || INT(i)) (first iteration)
|
||||||
|
prf.start(null, null);
|
||||||
|
prf.update(s);
|
||||||
|
prf.update(forge.util.int32ToBytes(i));
|
||||||
|
xor = u_c1 = prf.digest().getBytes();
|
||||||
|
|
||||||
|
// PRF(P, u_{c-1}) (other iterations)
|
||||||
|
for(var j = 2; j <= c; ++j) {
|
||||||
|
prf.start(null, null);
|
||||||
|
prf.update(u_c1);
|
||||||
|
u_c = prf.digest().getBytes();
|
||||||
|
// F(p, s, c, i)
|
||||||
|
xor = forge.util.xorBytes(xor, u_c, hLen);
|
||||||
|
u_c1 = u_c;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 4. Concatenate the blocks and extract the first dkLen octets to
|
||||||
|
produce a derived key DK:
|
||||||
|
|
||||||
|
DK = T_1 || T_2 || ... || T_len<0..r-1> */
|
||||||
|
dk += (i < len) ? xor : xor.substr(0, r);
|
||||||
|
}
|
||||||
|
/* 5. Output the derived key DK. */
|
||||||
|
return dk;
|
||||||
|
}
|
||||||
|
|
||||||
|
// async version
|
||||||
|
var i = 1, j;
|
||||||
|
function outer() {
|
||||||
|
if(i > len) {
|
||||||
|
// done
|
||||||
|
return callback(null, dk);
|
||||||
|
}
|
||||||
|
|
||||||
|
// PRF(P, S || INT(i)) (first iteration)
|
||||||
|
prf.start(null, null);
|
||||||
|
prf.update(s);
|
||||||
|
prf.update(forge.util.int32ToBytes(i));
|
||||||
|
xor = u_c1 = prf.digest().getBytes();
|
||||||
|
|
||||||
|
// PRF(P, u_{c-1}) (other iterations)
|
||||||
|
j = 2;
|
||||||
|
inner();
|
||||||
|
}
|
||||||
|
|
||||||
|
function inner() {
|
||||||
|
if(j <= c) {
|
||||||
|
prf.start(null, null);
|
||||||
|
prf.update(u_c1);
|
||||||
|
u_c = prf.digest().getBytes();
|
||||||
|
// F(p, s, c, i)
|
||||||
|
xor = forge.util.xorBytes(xor, u_c, hLen);
|
||||||
|
u_c1 = u_c;
|
||||||
|
++j;
|
||||||
|
return forge.util.setImmediate(inner);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 4. Concatenate the blocks and extract the first dkLen octets to
|
||||||
|
produce a derived key DK:
|
||||||
|
|
||||||
|
DK = T_1 || T_2 || ... || T_len<0..r-1> */
|
||||||
|
dk += (i < len) ? xor : xor.substr(0, r);
|
||||||
|
|
||||||
|
++i;
|
||||||
|
outer();
|
||||||
|
}
|
||||||
|
|
||||||
|
outer();
|
||||||
|
};
|
||||||
|
|
||||||
|
} // end module implementation
|
||||||
|
|
||||||
|
/* ########## Begin module wrapper ########## */
|
||||||
|
var name = 'pbkdf2';
|
||||||
|
if(typeof define !== 'function') {
|
||||||
|
// NodeJS -> AMD
|
||||||
|
if(typeof module === 'object' && module.exports) {
|
||||||
|
var nodeJS = true;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
factory(require, module);
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
// <script>
|
||||||
|
if(typeof forge === 'undefined') {
|
||||||
|
forge = {};
|
||||||
|
}
|
||||||
|
return initModule(forge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// AMD
|
||||||
|
var deps;
|
||||||
|
var defineFunc = function(require, module) {
|
||||||
|
module.exports = function(forge) {
|
||||||
|
var mods = deps.map(function(dep) {
|
||||||
|
return require(dep);
|
||||||
|
}).concat(initModule);
|
||||||
|
// handle circular dependencies
|
||||||
|
forge = forge || {};
|
||||||
|
forge.defined = forge.defined || {};
|
||||||
|
if(forge.defined[name]) {
|
||||||
|
return forge[name];
|
||||||
|
}
|
||||||
|
forge.defined[name] = true;
|
||||||
|
for(var i = 0; i < mods.length; ++i) {
|
||||||
|
mods[i](forge);
|
||||||
|
}
|
||||||
|
return forge[name];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
var tmpDefine = define;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
|
||||||
|
if(nodeJS) {
|
||||||
|
delete define;
|
||||||
|
return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
}
|
||||||
|
define = tmpDefine;
|
||||||
|
return define.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
};
|
||||||
|
define(['require', 'module', './hmac', './md', './util'], function() {
|
||||||
|
defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
});
|
||||||
|
})();
|
||||||
285
forge.js/pem.js
Normal file
@@ -0,0 +1,285 @@
|
|||||||
|
/**
|
||||||
|
* Javascript implementation of basic PEM (Privacy Enhanced Mail) algorithms.
|
||||||
|
*
|
||||||
|
* See: RFC 1421.
|
||||||
|
*
|
||||||
|
* @author Dave Longley
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013-2014 Digital Bazaar, Inc.
|
||||||
|
*
|
||||||
|
* A Forge PEM object has the following fields:
|
||||||
|
*
|
||||||
|
* type: identifies the type of message (eg: "RSA PRIVATE KEY").
|
||||||
|
*
|
||||||
|
* procType: identifies the type of processing performed on the message,
|
||||||
|
* it has two subfields: version and type, eg: 4,ENCRYPTED.
|
||||||
|
*
|
||||||
|
* contentDomain: identifies the type of content in the message, typically
|
||||||
|
* only uses the value: "RFC822".
|
||||||
|
*
|
||||||
|
* dekInfo: identifies the message encryption algorithm and mode and includes
|
||||||
|
* any parameters for the algorithm, it has two subfields: algorithm and
|
||||||
|
* parameters, eg: DES-CBC,F8143EDE5960C597.
|
||||||
|
*
|
||||||
|
* headers: contains all other PEM encapsulated headers -- where order is
|
||||||
|
* significant (for pairing data like recipient ID + key info).
|
||||||
|
*
|
||||||
|
* body: the binary-encoded body.
|
||||||
|
*/
|
||||||
|
(function() {
|
||||||
|
/* ########## Begin module implementation ########## */
|
||||||
|
function initModule(forge) {
|
||||||
|
|
||||||
|
// shortcut for pem API
|
||||||
|
var pem = forge.pem = forge.pem || {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encodes (serializes) the given PEM object.
|
||||||
|
*
|
||||||
|
* @param msg the PEM message object to encode.
|
||||||
|
* @param options the options to use:
|
||||||
|
* maxline the maximum characters per line for the body, (default: 64).
|
||||||
|
*
|
||||||
|
* @return the PEM-formatted string.
|
||||||
|
*/
|
||||||
|
pem.encode = function(msg, options) {
|
||||||
|
options = options || {};
|
||||||
|
var rval = '-----BEGIN ' + msg.type + '-----\r\n';
|
||||||
|
|
||||||
|
// encode special headers
|
||||||
|
var header;
|
||||||
|
if(msg.procType) {
|
||||||
|
header = {
|
||||||
|
name: 'Proc-Type',
|
||||||
|
values: [String(msg.procType.version), msg.procType.type]
|
||||||
|
};
|
||||||
|
rval += foldHeader(header);
|
||||||
|
}
|
||||||
|
if(msg.contentDomain) {
|
||||||
|
header = {name: 'Content-Domain', values: [msg.contentDomain]};
|
||||||
|
rval += foldHeader(header);
|
||||||
|
}
|
||||||
|
if(msg.dekInfo) {
|
||||||
|
header = {name: 'DEK-Info', values: [msg.dekInfo.algorithm]};
|
||||||
|
if(msg.dekInfo.parameters) {
|
||||||
|
header.values.push(msg.dekInfo.parameters);
|
||||||
|
}
|
||||||
|
rval += foldHeader(header);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(msg.headers) {
|
||||||
|
// encode all other headers
|
||||||
|
for(var i = 0; i < msg.headers.length; ++i) {
|
||||||
|
rval += foldHeader(msg.headers[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// terminate header
|
||||||
|
if(msg.procType) {
|
||||||
|
rval += '\r\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
// add body
|
||||||
|
rval += forge.util.encode64(msg.body, options.maxline || 64) + '\r\n';
|
||||||
|
|
||||||
|
rval += '-----END ' + msg.type + '-----\r\n';
|
||||||
|
return rval;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decodes (deserializes) all PEM messages found in the given string.
|
||||||
|
*
|
||||||
|
* @param str the PEM-formatted string to decode.
|
||||||
|
*
|
||||||
|
* @return the PEM message objects in an array.
|
||||||
|
*/
|
||||||
|
pem.decode = function(str) {
|
||||||
|
var rval = [];
|
||||||
|
|
||||||
|
// split string into PEM messages (be lenient w/EOF on BEGIN line)
|
||||||
|
var rMessage = /\s*-----BEGIN ([A-Z0-9- ]+)-----\r?\n?([\x21-\x7e\s]+?(?:\r?\n\r?\n))?([:A-Za-z0-9+\/=\s]+?)-----END \1-----/g;
|
||||||
|
var rHeader = /([\x21-\x7e]+):\s*([\x21-\x7e\s^:]+)/;
|
||||||
|
var rCRLF = /\r?\n/;
|
||||||
|
var match;
|
||||||
|
while(true) {
|
||||||
|
match = rMessage.exec(str);
|
||||||
|
if(!match) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
var msg = {
|
||||||
|
type: match[1],
|
||||||
|
procType: null,
|
||||||
|
contentDomain: null,
|
||||||
|
dekInfo: null,
|
||||||
|
headers: [],
|
||||||
|
body: forge.util.decode64(match[3])
|
||||||
|
};
|
||||||
|
rval.push(msg);
|
||||||
|
|
||||||
|
// no headers
|
||||||
|
if(!match[2]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse headers
|
||||||
|
var lines = match[2].split(rCRLF);
|
||||||
|
var li = 0;
|
||||||
|
while(match && li < lines.length) {
|
||||||
|
// get line, trim any rhs whitespace
|
||||||
|
var line = lines[li].replace(/\s+$/, '');
|
||||||
|
|
||||||
|
// RFC2822 unfold any following folded lines
|
||||||
|
for(var nl = li + 1; nl < lines.length; ++nl) {
|
||||||
|
var next = lines[nl];
|
||||||
|
if(!/\s/.test(next[0])) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
line += next;
|
||||||
|
li = nl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse header
|
||||||
|
match = line.match(rHeader);
|
||||||
|
if(match) {
|
||||||
|
var header = {name: match[1], values: []};
|
||||||
|
var values = match[2].split(',');
|
||||||
|
for(var vi = 0; vi < values.length; ++vi) {
|
||||||
|
header.values.push(ltrim(values[vi]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Proc-Type must be the first header
|
||||||
|
if(!msg.procType) {
|
||||||
|
if(header.name !== 'Proc-Type') {
|
||||||
|
throw new Error('Invalid PEM formatted message. The first ' +
|
||||||
|
'encapsulated header must be "Proc-Type".');
|
||||||
|
} else if(header.values.length !== 2) {
|
||||||
|
throw new Error('Invalid PEM formatted message. The "Proc-Type" ' +
|
||||||
|
'header must have two subfields.');
|
||||||
|
}
|
||||||
|
msg.procType = {version: values[0], type: values[1]};
|
||||||
|
} else if(!msg.contentDomain && header.name === 'Content-Domain') {
|
||||||
|
// special-case Content-Domain
|
||||||
|
msg.contentDomain = values[0] || '';
|
||||||
|
} else if(!msg.dekInfo && header.name === 'DEK-Info') {
|
||||||
|
// special-case DEK-Info
|
||||||
|
if(header.values.length === 0) {
|
||||||
|
throw new Error('Invalid PEM formatted message. The "DEK-Info" ' +
|
||||||
|
'header must have at least one subfield.');
|
||||||
|
}
|
||||||
|
msg.dekInfo = {algorithm: values[0], parameters: values[1] || null};
|
||||||
|
} else {
|
||||||
|
msg.headers.push(header);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
++li;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(msg.procType === 'ENCRYPTED' && !msg.dekInfo) {
|
||||||
|
throw new Error('Invalid PEM formatted message. The "DEK-Info" ' +
|
||||||
|
'header must be present if "Proc-Type" is "ENCRYPTED".');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(rval.length === 0) {
|
||||||
|
throw new Error('Invalid PEM formatted message.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return rval;
|
||||||
|
};
|
||||||
|
|
||||||
|
function foldHeader(header) {
|
||||||
|
var rval = header.name + ': ';
|
||||||
|
|
||||||
|
// ensure values with CRLF are folded
|
||||||
|
var values = [];
|
||||||
|
var insertSpace = function(match, $1) {
|
||||||
|
return ' ' + $1;
|
||||||
|
};
|
||||||
|
for(var i = 0; i < header.values.length; ++i) {
|
||||||
|
values.push(header.values[i].replace(/^(\S+\r\n)/, insertSpace));
|
||||||
|
}
|
||||||
|
rval += values.join(',') + '\r\n';
|
||||||
|
|
||||||
|
// do folding
|
||||||
|
var length = 0;
|
||||||
|
var candidate = -1;
|
||||||
|
for(var i = 0; i < rval.length; ++i, ++length) {
|
||||||
|
if(length > 65 && candidate !== -1) {
|
||||||
|
var insert = rval[candidate];
|
||||||
|
if(insert === ',') {
|
||||||
|
++candidate;
|
||||||
|
rval = rval.substr(0, candidate) + '\r\n ' + rval.substr(candidate);
|
||||||
|
} else {
|
||||||
|
rval = rval.substr(0, candidate) +
|
||||||
|
'\r\n' + insert + rval.substr(candidate + 1);
|
||||||
|
}
|
||||||
|
length = (i - candidate - 1);
|
||||||
|
candidate = -1;
|
||||||
|
++i;
|
||||||
|
} else if(rval[i] === ' ' || rval[i] === '\t' || rval[i] === ',') {
|
||||||
|
candidate = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rval;
|
||||||
|
}
|
||||||
|
|
||||||
|
function ltrim(str) {
|
||||||
|
return str.replace(/^\s+/, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end module implementation
|
||||||
|
|
||||||
|
/* ########## Begin module wrapper ########## */
|
||||||
|
var name = 'pem';
|
||||||
|
if(typeof define !== 'function') {
|
||||||
|
// NodeJS -> AMD
|
||||||
|
if(typeof module === 'object' && module.exports) {
|
||||||
|
var nodeJS = true;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
factory(require, module);
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
// <script>
|
||||||
|
if(typeof forge === 'undefined') {
|
||||||
|
forge = {};
|
||||||
|
}
|
||||||
|
return initModule(forge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// AMD
|
||||||
|
var deps;
|
||||||
|
var defineFunc = function(require, module) {
|
||||||
|
module.exports = function(forge) {
|
||||||
|
var mods = deps.map(function(dep) {
|
||||||
|
return require(dep);
|
||||||
|
}).concat(initModule);
|
||||||
|
// handle circular dependencies
|
||||||
|
forge = forge || {};
|
||||||
|
forge.defined = forge.defined || {};
|
||||||
|
if(forge.defined[name]) {
|
||||||
|
return forge[name];
|
||||||
|
}
|
||||||
|
forge.defined[name] = true;
|
||||||
|
for(var i = 0; i < mods.length; ++i) {
|
||||||
|
mods[i](forge);
|
||||||
|
}
|
||||||
|
return forge[name];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
var tmpDefine = define;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
|
||||||
|
if(nodeJS) {
|
||||||
|
delete define;
|
||||||
|
return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
}
|
||||||
|
define = tmpDefine;
|
||||||
|
return define.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
};
|
||||||
|
define(['require', 'module', './util'], function() {
|
||||||
|
defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
});
|
||||||
|
})();
|
||||||
329
forge.js/pkcs1.js
Normal file
@@ -0,0 +1,329 @@
|
|||||||
|
/**
|
||||||
|
* Partial implementation of PKCS#1 v2.2: RSA-OEAP
|
||||||
|
*
|
||||||
|
* Modified but based on the following MIT and BSD licensed code:
|
||||||
|
*
|
||||||
|
* https://github.com/kjur/jsjws/blob/master/rsa.js:
|
||||||
|
*
|
||||||
|
* The 'jsjws'(JSON Web Signature JavaScript Library) License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2012 Kenji Urushima
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* http://webrsa.cvs.sourceforge.net/viewvc/webrsa/Client/RSAES-OAEP.js?content-type=text%2Fplain:
|
||||||
|
*
|
||||||
|
* RSAES-OAEP.js
|
||||||
|
* $Id: RSAES-OAEP.js,v 1.1.1.1 2003/03/19 15:37:20 ellispritchard Exp $
|
||||||
|
* JavaScript Implementation of PKCS #1 v2.1 RSA CRYPTOGRAPHY STANDARD (RSA Laboratories, June 14, 2002)
|
||||||
|
* Copyright (C) Ellis Pritchard, Guardian Unlimited 2003.
|
||||||
|
* Contact: ellis@nukinetics.com
|
||||||
|
* Distributed under the BSD License.
|
||||||
|
*
|
||||||
|
* Official documentation: http://www.rsa.com/rsalabs/node.asp?id=2125
|
||||||
|
*
|
||||||
|
* @author Evan Jones (http://evanjones.ca/)
|
||||||
|
* @author Dave Longley
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013-2014 Digital Bazaar, Inc.
|
||||||
|
*/
|
||||||
|
(function() {
|
||||||
|
/* ########## Begin module implementation ########## */
|
||||||
|
function initModule(forge) {
|
||||||
|
|
||||||
|
// shortcut for PKCS#1 API
|
||||||
|
var pkcs1 = forge.pkcs1 = forge.pkcs1 || {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encode the given RSAES-OAEP message (M) using key, with optional label (L)
|
||||||
|
* and seed.
|
||||||
|
*
|
||||||
|
* This method does not perform RSA encryption, it only encodes the message
|
||||||
|
* using RSAES-OAEP.
|
||||||
|
*
|
||||||
|
* @param key the RSA key to use.
|
||||||
|
* @param message the message to encode.
|
||||||
|
* @param options the options to use:
|
||||||
|
* label an optional label to use.
|
||||||
|
* seed the seed to use.
|
||||||
|
* md the message digest object to use, undefined for SHA-1.
|
||||||
|
* mgf1 optional mgf1 parameters:
|
||||||
|
* md the message digest object to use for MGF1.
|
||||||
|
*
|
||||||
|
* @return the encoded message bytes.
|
||||||
|
*/
|
||||||
|
pkcs1.encode_rsa_oaep = function(key, message, options) {
|
||||||
|
// parse arguments
|
||||||
|
var label;
|
||||||
|
var seed;
|
||||||
|
var md;
|
||||||
|
var mgf1Md;
|
||||||
|
// legacy args (label, seed, md)
|
||||||
|
if(typeof options === 'string') {
|
||||||
|
label = options;
|
||||||
|
seed = arguments[3] || undefined;
|
||||||
|
md = arguments[4] || undefined;
|
||||||
|
} else if(options) {
|
||||||
|
label = options.label || undefined;
|
||||||
|
seed = options.seed || undefined;
|
||||||
|
md = options.md || undefined;
|
||||||
|
if(options.mgf1 && options.mgf1.md) {
|
||||||
|
mgf1Md = options.mgf1.md;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// default OAEP to SHA-1 message digest
|
||||||
|
if(!md) {
|
||||||
|
md = forge.md.sha1.create();
|
||||||
|
} else {
|
||||||
|
md.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
// default MGF-1 to same as OAEP
|
||||||
|
if(!mgf1Md) {
|
||||||
|
mgf1Md = md;
|
||||||
|
}
|
||||||
|
|
||||||
|
// compute length in bytes and check output
|
||||||
|
var keyLength = Math.ceil(key.n.bitLength() / 8);
|
||||||
|
var maxLength = keyLength - 2 * md.digestLength - 2;
|
||||||
|
if(message.length > maxLength) {
|
||||||
|
var error = new Error('RSAES-OAEP input message length is too long.');
|
||||||
|
error.length = message.length;
|
||||||
|
error.maxLength = maxLength;
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!label) {
|
||||||
|
label = '';
|
||||||
|
}
|
||||||
|
md.update(label, 'raw');
|
||||||
|
var lHash = md.digest();
|
||||||
|
|
||||||
|
var PS = '';
|
||||||
|
var PS_length = maxLength - message.length;
|
||||||
|
for (var i = 0; i < PS_length; i++) {
|
||||||
|
PS += '\x00';
|
||||||
|
}
|
||||||
|
|
||||||
|
var DB = lHash.getBytes() + PS + '\x01' + message;
|
||||||
|
|
||||||
|
if(!seed) {
|
||||||
|
seed = forge.random.getBytes(md.digestLength);
|
||||||
|
} else if(seed.length !== md.digestLength) {
|
||||||
|
var error = new Error('Invalid RSAES-OAEP seed. The seed length must ' +
|
||||||
|
'match the digest length.')
|
||||||
|
error.seedLength = seed.length;
|
||||||
|
error.digestLength = md.digestLength;
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
var dbMask = rsa_mgf1(seed, keyLength - md.digestLength - 1, mgf1Md);
|
||||||
|
var maskedDB = forge.util.xorBytes(DB, dbMask, DB.length);
|
||||||
|
|
||||||
|
var seedMask = rsa_mgf1(maskedDB, md.digestLength, mgf1Md);
|
||||||
|
var maskedSeed = forge.util.xorBytes(seed, seedMask, seed.length);
|
||||||
|
|
||||||
|
// return encoded message
|
||||||
|
return '\x00' + maskedSeed + maskedDB;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decode the given RSAES-OAEP encoded message (EM) using key, with optional
|
||||||
|
* label (L).
|
||||||
|
*
|
||||||
|
* This method does not perform RSA decryption, it only decodes the message
|
||||||
|
* using RSAES-OAEP.
|
||||||
|
*
|
||||||
|
* @param key the RSA key to use.
|
||||||
|
* @param em the encoded message to decode.
|
||||||
|
* @param options the options to use:
|
||||||
|
* label an optional label to use.
|
||||||
|
* md the message digest object to use for OAEP, undefined for SHA-1.
|
||||||
|
* mgf1 optional mgf1 parameters:
|
||||||
|
* md the message digest object to use for MGF1.
|
||||||
|
*
|
||||||
|
* @return the decoded message bytes.
|
||||||
|
*/
|
||||||
|
pkcs1.decode_rsa_oaep = function(key, em, options) {
|
||||||
|
// parse args
|
||||||
|
var label;
|
||||||
|
var md;
|
||||||
|
var mgf1Md;
|
||||||
|
// legacy args
|
||||||
|
if(typeof options === 'string') {
|
||||||
|
label = options;
|
||||||
|
md = arguments[3] || undefined;
|
||||||
|
} else if(options) {
|
||||||
|
label = options.label || undefined;
|
||||||
|
md = options.md || undefined;
|
||||||
|
if(options.mgf1 && options.mgf1.md) {
|
||||||
|
mgf1Md = options.mgf1.md;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// compute length in bytes
|
||||||
|
var keyLength = Math.ceil(key.n.bitLength() / 8);
|
||||||
|
|
||||||
|
if(em.length !== keyLength) {
|
||||||
|
var error = new Error('RSAES-OAEP encoded message length is invalid.');
|
||||||
|
error.length = em.length;
|
||||||
|
error.expectedLength = keyLength;
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
// default OAEP to SHA-1 message digest
|
||||||
|
if(md === undefined) {
|
||||||
|
md = forge.md.sha1.create();
|
||||||
|
} else {
|
||||||
|
md.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
// default MGF-1 to same as OAEP
|
||||||
|
if(!mgf1Md) {
|
||||||
|
mgf1Md = md;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(keyLength < 2 * md.digestLength + 2) {
|
||||||
|
throw new Error('RSAES-OAEP key is too short for the hash function.');
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!label) {
|
||||||
|
label = '';
|
||||||
|
}
|
||||||
|
md.update(label, 'raw');
|
||||||
|
var lHash = md.digest().getBytes();
|
||||||
|
|
||||||
|
// split the message into its parts
|
||||||
|
var y = em.charAt(0);
|
||||||
|
var maskedSeed = em.substring(1, md.digestLength + 1);
|
||||||
|
var maskedDB = em.substring(1 + md.digestLength);
|
||||||
|
|
||||||
|
var seedMask = rsa_mgf1(maskedDB, md.digestLength, mgf1Md);
|
||||||
|
var seed = forge.util.xorBytes(maskedSeed, seedMask, maskedSeed.length);
|
||||||
|
|
||||||
|
var dbMask = rsa_mgf1(seed, keyLength - md.digestLength - 1, mgf1Md);
|
||||||
|
var db = forge.util.xorBytes(maskedDB, dbMask, maskedDB.length);
|
||||||
|
|
||||||
|
var lHashPrime = db.substring(0, md.digestLength);
|
||||||
|
|
||||||
|
// constant time check that all values match what is expected
|
||||||
|
var error = (y !== '\x00');
|
||||||
|
|
||||||
|
// constant time check lHash vs lHashPrime
|
||||||
|
for(var i = 0; i < md.digestLength; ++i) {
|
||||||
|
error |= (lHash.charAt(i) !== lHashPrime.charAt(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
// "constant time" find the 0x1 byte separating the padding (zeros) from the
|
||||||
|
// message
|
||||||
|
// TODO: It must be possible to do this in a better/smarter way?
|
||||||
|
var in_ps = 1;
|
||||||
|
var index = md.digestLength;
|
||||||
|
for(var j = md.digestLength; j < db.length; j++) {
|
||||||
|
var code = db.charCodeAt(j);
|
||||||
|
|
||||||
|
var is_0 = (code & 0x1) ^ 0x1;
|
||||||
|
|
||||||
|
// non-zero if not 0 or 1 in the ps section
|
||||||
|
var error_mask = in_ps ? 0xfffe : 0x0000;
|
||||||
|
error |= (code & error_mask);
|
||||||
|
|
||||||
|
// latch in_ps to zero after we find 0x1
|
||||||
|
in_ps = in_ps & is_0;
|
||||||
|
index += in_ps;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(error || db.charCodeAt(index) !== 0x1) {
|
||||||
|
throw new Error('Invalid RSAES-OAEP padding.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return db.substring(index + 1);
|
||||||
|
};
|
||||||
|
|
||||||
|
function rsa_mgf1(seed, maskLength, hash) {
|
||||||
|
// default to SHA-1 message digest
|
||||||
|
if(!hash) {
|
||||||
|
hash = forge.md.sha1.create();
|
||||||
|
}
|
||||||
|
var t = '';
|
||||||
|
var count = Math.ceil(maskLength / hash.digestLength);
|
||||||
|
for(var i = 0; i < count; ++i) {
|
||||||
|
var c = String.fromCharCode(
|
||||||
|
(i >> 24) & 0xFF, (i >> 16) & 0xFF, (i >> 8) & 0xFF, i & 0xFF);
|
||||||
|
hash.start();
|
||||||
|
hash.update(seed + c);
|
||||||
|
t += hash.digest().getBytes();
|
||||||
|
}
|
||||||
|
return t.substring(0, maskLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end module implementation
|
||||||
|
|
||||||
|
/* ########## Begin module wrapper ########## */
|
||||||
|
var name = 'pkcs1';
|
||||||
|
if(typeof define !== 'function') {
|
||||||
|
// NodeJS -> AMD
|
||||||
|
if(typeof module === 'object' && module.exports) {
|
||||||
|
var nodeJS = true;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
factory(require, module);
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
// <script>
|
||||||
|
if(typeof forge === 'undefined') {
|
||||||
|
forge = {};
|
||||||
|
}
|
||||||
|
return initModule(forge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// AMD
|
||||||
|
var deps;
|
||||||
|
var defineFunc = function(require, module) {
|
||||||
|
module.exports = function(forge) {
|
||||||
|
var mods = deps.map(function(dep) {
|
||||||
|
return require(dep);
|
||||||
|
}).concat(initModule);
|
||||||
|
// handle circular dependencies
|
||||||
|
forge = forge || {};
|
||||||
|
forge.defined = forge.defined || {};
|
||||||
|
if(forge.defined[name]) {
|
||||||
|
return forge[name];
|
||||||
|
}
|
||||||
|
forge.defined[name] = true;
|
||||||
|
for(var i = 0; i < mods.length; ++i) {
|
||||||
|
mods[i](forge);
|
||||||
|
}
|
||||||
|
return forge[name];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
var tmpDefine = define;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
|
||||||
|
if(nodeJS) {
|
||||||
|
delete define;
|
||||||
|
return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
}
|
||||||
|
define = tmpDefine;
|
||||||
|
return define.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
};
|
||||||
|
define(['require', 'module', './util', './random', './sha1'], function() {
|
||||||
|
defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
});
|
||||||
|
})();
|
||||||
1133
forge.js/pkcs12.js
Normal file
1301
forge.js/pkcs7.js
Normal file
463
forge.js/pkcs7asn1.js
Normal file
@@ -0,0 +1,463 @@
|
|||||||
|
/**
|
||||||
|
* Javascript implementation of ASN.1 validators for PKCS#7 v1.5.
|
||||||
|
*
|
||||||
|
* @author Dave Longley
|
||||||
|
* @author Stefan Siegl
|
||||||
|
*
|
||||||
|
* Copyright (c) 2012-2015 Digital Bazaar, Inc.
|
||||||
|
* Copyright (c) 2012 Stefan Siegl <stesie@brokenpipe.de>
|
||||||
|
*
|
||||||
|
* The ASN.1 representation of PKCS#7 is as follows
|
||||||
|
* (see RFC #2315 for details, http://www.ietf.org/rfc/rfc2315.txt):
|
||||||
|
*
|
||||||
|
* A PKCS#7 message consists of a ContentInfo on root level, which may
|
||||||
|
* contain any number of further ContentInfo nested into it.
|
||||||
|
*
|
||||||
|
* ContentInfo ::= SEQUENCE {
|
||||||
|
* contentType ContentType,
|
||||||
|
* content [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* ContentType ::= OBJECT IDENTIFIER
|
||||||
|
*
|
||||||
|
* EnvelopedData ::= SEQUENCE {
|
||||||
|
* version Version,
|
||||||
|
* recipientInfos RecipientInfos,
|
||||||
|
* encryptedContentInfo EncryptedContentInfo
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* EncryptedData ::= SEQUENCE {
|
||||||
|
* version Version,
|
||||||
|
* encryptedContentInfo EncryptedContentInfo
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* id-signedData OBJECT IDENTIFIER ::= { iso(1) member-body(2)
|
||||||
|
* us(840) rsadsi(113549) pkcs(1) pkcs7(7) 2 }
|
||||||
|
*
|
||||||
|
* SignedData ::= SEQUENCE {
|
||||||
|
* version INTEGER,
|
||||||
|
* digestAlgorithms DigestAlgorithmIdentifiers,
|
||||||
|
* contentInfo ContentInfo,
|
||||||
|
* certificates [0] IMPLICIT Certificates OPTIONAL,
|
||||||
|
* crls [1] IMPLICIT CertificateRevocationLists OPTIONAL,
|
||||||
|
* signerInfos SignerInfos
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* SignerInfos ::= SET OF SignerInfo
|
||||||
|
*
|
||||||
|
* SignerInfo ::= SEQUENCE {
|
||||||
|
* version Version,
|
||||||
|
* issuerAndSerialNumber IssuerAndSerialNumber,
|
||||||
|
* digestAlgorithm DigestAlgorithmIdentifier,
|
||||||
|
* authenticatedAttributes [0] IMPLICIT Attributes OPTIONAL,
|
||||||
|
* digestEncryptionAlgorithm DigestEncryptionAlgorithmIdentifier,
|
||||||
|
* encryptedDigest EncryptedDigest,
|
||||||
|
* unauthenticatedAttributes [1] IMPLICIT Attributes OPTIONAL
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* EncryptedDigest ::= OCTET STRING
|
||||||
|
*
|
||||||
|
* Attributes ::= SET OF Attribute
|
||||||
|
*
|
||||||
|
* Attribute ::= SEQUENCE {
|
||||||
|
* attrType OBJECT IDENTIFIER,
|
||||||
|
* attrValues SET OF AttributeValue
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* AttributeValue ::= ANY
|
||||||
|
*
|
||||||
|
* Version ::= INTEGER
|
||||||
|
*
|
||||||
|
* RecipientInfos ::= SET OF RecipientInfo
|
||||||
|
*
|
||||||
|
* EncryptedContentInfo ::= SEQUENCE {
|
||||||
|
* contentType ContentType,
|
||||||
|
* contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier,
|
||||||
|
* encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* ContentEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
|
||||||
|
*
|
||||||
|
* The AlgorithmIdentifier contains an Object Identifier (OID) and parameters
|
||||||
|
* for the algorithm, if any. In the case of AES and DES3, there is only one,
|
||||||
|
* the IV.
|
||||||
|
*
|
||||||
|
* AlgorithmIdentifer ::= SEQUENCE {
|
||||||
|
* algorithm OBJECT IDENTIFIER,
|
||||||
|
* parameters ANY DEFINED BY algorithm OPTIONAL
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* EncryptedContent ::= OCTET STRING
|
||||||
|
*
|
||||||
|
* RecipientInfo ::= SEQUENCE {
|
||||||
|
* version Version,
|
||||||
|
* issuerAndSerialNumber IssuerAndSerialNumber,
|
||||||
|
* keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier,
|
||||||
|
* encryptedKey EncryptedKey
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* IssuerAndSerialNumber ::= SEQUENCE {
|
||||||
|
* issuer Name,
|
||||||
|
* serialNumber CertificateSerialNumber
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* CertificateSerialNumber ::= INTEGER
|
||||||
|
*
|
||||||
|
* KeyEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
|
||||||
|
*
|
||||||
|
* EncryptedKey ::= OCTET STRING
|
||||||
|
*/
|
||||||
|
(function() {
|
||||||
|
/* ########## Begin module implementation ########## */
|
||||||
|
function initModule(forge) {
|
||||||
|
|
||||||
|
// shortcut for ASN.1 API
|
||||||
|
var asn1 = forge.asn1;
|
||||||
|
|
||||||
|
// shortcut for PKCS#7 API
|
||||||
|
var p7v = forge.pkcs7asn1 = forge.pkcs7asn1 || {};
|
||||||
|
forge.pkcs7 = forge.pkcs7 || {};
|
||||||
|
forge.pkcs7.asn1 = p7v;
|
||||||
|
|
||||||
|
var contentInfoValidator = {
|
||||||
|
name: 'ContentInfo',
|
||||||
|
tagClass: asn1.Class.UNIVERSAL,
|
||||||
|
type: asn1.Type.SEQUENCE,
|
||||||
|
constructed: true,
|
||||||
|
value: [{
|
||||||
|
name: 'ContentInfo.ContentType',
|
||||||
|
tagClass: asn1.Class.UNIVERSAL,
|
||||||
|
type: asn1.Type.OID,
|
||||||
|
constructed: false,
|
||||||
|
capture: 'contentType'
|
||||||
|
}, {
|
||||||
|
name: 'ContentInfo.content',
|
||||||
|
tagClass: asn1.Class.CONTEXT_SPECIFIC,
|
||||||
|
type: 0,
|
||||||
|
constructed: true,
|
||||||
|
optional: true,
|
||||||
|
captureAsn1: 'content'
|
||||||
|
}]
|
||||||
|
};
|
||||||
|
p7v.contentInfoValidator = contentInfoValidator;
|
||||||
|
|
||||||
|
var encryptedContentInfoValidator = {
|
||||||
|
name: 'EncryptedContentInfo',
|
||||||
|
tagClass: asn1.Class.UNIVERSAL,
|
||||||
|
type: asn1.Type.SEQUENCE,
|
||||||
|
constructed: true,
|
||||||
|
value: [{
|
||||||
|
name: 'EncryptedContentInfo.contentType',
|
||||||
|
tagClass: asn1.Class.UNIVERSAL,
|
||||||
|
type: asn1.Type.OID,
|
||||||
|
constructed: false,
|
||||||
|
capture: 'contentType'
|
||||||
|
}, {
|
||||||
|
name: 'EncryptedContentInfo.contentEncryptionAlgorithm',
|
||||||
|
tagClass: asn1.Class.UNIVERSAL,
|
||||||
|
type: asn1.Type.SEQUENCE,
|
||||||
|
constructed: true,
|
||||||
|
value: [{
|
||||||
|
name: 'EncryptedContentInfo.contentEncryptionAlgorithm.algorithm',
|
||||||
|
tagClass: asn1.Class.UNIVERSAL,
|
||||||
|
type: asn1.Type.OID,
|
||||||
|
constructed: false,
|
||||||
|
capture: 'encAlgorithm'
|
||||||
|
}, {
|
||||||
|
name: 'EncryptedContentInfo.contentEncryptionAlgorithm.parameter',
|
||||||
|
tagClass: asn1.Class.UNIVERSAL,
|
||||||
|
captureAsn1: 'encParameter'
|
||||||
|
}]
|
||||||
|
}, {
|
||||||
|
name: 'EncryptedContentInfo.encryptedContent',
|
||||||
|
tagClass: asn1.Class.CONTEXT_SPECIFIC,
|
||||||
|
type: 0,
|
||||||
|
/* The PKCS#7 structure output by OpenSSL somewhat differs from what
|
||||||
|
* other implementations do generate.
|
||||||
|
*
|
||||||
|
* OpenSSL generates a structure like this:
|
||||||
|
* SEQUENCE {
|
||||||
|
* ...
|
||||||
|
* [0]
|
||||||
|
* 26 DA 67 D2 17 9C 45 3C B1 2A A8 59 2F 29 33 38
|
||||||
|
* C3 C3 DF 86 71 74 7A 19 9F 40 D0 29 BE 85 90 45
|
||||||
|
* ...
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* Whereas other implementations (and this PKCS#7 module) generate:
|
||||||
|
* SEQUENCE {
|
||||||
|
* ...
|
||||||
|
* [0] {
|
||||||
|
* OCTET STRING
|
||||||
|
* 26 DA 67 D2 17 9C 45 3C B1 2A A8 59 2F 29 33 38
|
||||||
|
* C3 C3 DF 86 71 74 7A 19 9F 40 D0 29 BE 85 90 45
|
||||||
|
* ...
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* In order to support both, we just capture the context specific
|
||||||
|
* field here. The OCTET STRING bit is removed below.
|
||||||
|
*/
|
||||||
|
capture: 'encryptedContent',
|
||||||
|
captureAsn1: 'encryptedContentAsn1'
|
||||||
|
}]
|
||||||
|
};
|
||||||
|
|
||||||
|
p7v.envelopedDataValidator = {
|
||||||
|
name: 'EnvelopedData',
|
||||||
|
tagClass: asn1.Class.UNIVERSAL,
|
||||||
|
type: asn1.Type.SEQUENCE,
|
||||||
|
constructed: true,
|
||||||
|
value: [{
|
||||||
|
name: 'EnvelopedData.Version',
|
||||||
|
tagClass: asn1.Class.UNIVERSAL,
|
||||||
|
type: asn1.Type.INTEGER,
|
||||||
|
constructed: false,
|
||||||
|
capture: 'version'
|
||||||
|
}, {
|
||||||
|
name: 'EnvelopedData.RecipientInfos',
|
||||||
|
tagClass: asn1.Class.UNIVERSAL,
|
||||||
|
type: asn1.Type.SET,
|
||||||
|
constructed: true,
|
||||||
|
captureAsn1: 'recipientInfos'
|
||||||
|
}].concat(encryptedContentInfoValidator)
|
||||||
|
};
|
||||||
|
|
||||||
|
p7v.encryptedDataValidator = {
|
||||||
|
name: 'EncryptedData',
|
||||||
|
tagClass: asn1.Class.UNIVERSAL,
|
||||||
|
type: asn1.Type.SEQUENCE,
|
||||||
|
constructed: true,
|
||||||
|
value: [{
|
||||||
|
name: 'EncryptedData.Version',
|
||||||
|
tagClass: asn1.Class.UNIVERSAL,
|
||||||
|
type: asn1.Type.INTEGER,
|
||||||
|
constructed: false,
|
||||||
|
capture: 'version'
|
||||||
|
}].concat(encryptedContentInfoValidator)
|
||||||
|
};
|
||||||
|
|
||||||
|
var signerValidator = {
|
||||||
|
name: 'SignerInfo',
|
||||||
|
tagClass: asn1.Class.UNIVERSAL,
|
||||||
|
type: asn1.Type.SEQUENCE,
|
||||||
|
constructed: true,
|
||||||
|
value: [{
|
||||||
|
name: 'SignerInfo.version',
|
||||||
|
tagClass: asn1.Class.UNIVERSAL,
|
||||||
|
type: asn1.Type.INTEGER,
|
||||||
|
constructed: false
|
||||||
|
}, {
|
||||||
|
name: 'SignerInfo.issuerAndSerialNumber',
|
||||||
|
tagClass: asn1.Class.UNIVERSAL,
|
||||||
|
type: asn1.Type.SEQUENCE,
|
||||||
|
constructed: true,
|
||||||
|
value: [{
|
||||||
|
name: 'SignerInfo.issuerAndSerialNumber.issuer',
|
||||||
|
tagClass: asn1.Class.UNIVERSAL,
|
||||||
|
type: asn1.Type.SEQUENCE,
|
||||||
|
constructed: true,
|
||||||
|
captureAsn1: 'issuer'
|
||||||
|
}, {
|
||||||
|
name: 'SignerInfo.issuerAndSerialNumber.serialNumber',
|
||||||
|
tagClass: asn1.Class.UNIVERSAL,
|
||||||
|
type: asn1.Type.INTEGER,
|
||||||
|
constructed: false,
|
||||||
|
capture: 'serial'
|
||||||
|
}]
|
||||||
|
}, {
|
||||||
|
name: 'SignerInfo.digestAlgorithm',
|
||||||
|
tagClass: asn1.Class.UNIVERSAL,
|
||||||
|
type: asn1.Type.SEQUENCE,
|
||||||
|
constructed: true,
|
||||||
|
value: [{
|
||||||
|
name: 'SignerInfo.digestAlgorithm.algorithm',
|
||||||
|
tagClass: asn1.Class.UNIVERSAL,
|
||||||
|
type: asn1.Type.OID,
|
||||||
|
constructed: false,
|
||||||
|
capture: 'digestAlgorithm'
|
||||||
|
}, {
|
||||||
|
name: 'SignerInfo.digestAlgorithm.parameter',
|
||||||
|
tagClass: asn1.Class.UNIVERSAL,
|
||||||
|
constructed: false,
|
||||||
|
captureAsn1: 'digestParameter',
|
||||||
|
optional: true
|
||||||
|
}]
|
||||||
|
}, {
|
||||||
|
name: 'SignerInfo.authenticatedAttributes',
|
||||||
|
tagClass: asn1.Class.CONTEXT_SPECIFIC,
|
||||||
|
type: 0,
|
||||||
|
constructed: true,
|
||||||
|
optional: true,
|
||||||
|
capture: 'authenticatedAttributes'
|
||||||
|
}, {
|
||||||
|
name: 'SignerInfo.digestEncryptionAlgorithm',
|
||||||
|
tagClass: asn1.Class.UNIVERSAL,
|
||||||
|
type: asn1.Type.SEQUENCE,
|
||||||
|
constructed: true,
|
||||||
|
capture: 'signatureAlgorithm'
|
||||||
|
}, {
|
||||||
|
name: 'SignerInfo.encryptedDigest',
|
||||||
|
tagClass: asn1.Class.UNIVERSAL,
|
||||||
|
type: asn1.Type.OCTETSTRING,
|
||||||
|
constructed: false,
|
||||||
|
capture: 'signature'
|
||||||
|
}, {
|
||||||
|
name: 'SignerInfo.unauthenticatedAttributes',
|
||||||
|
tagClass: asn1.Class.CONTEXT_SPECIFIC,
|
||||||
|
type: 1,
|
||||||
|
constructed: true,
|
||||||
|
optional: true,
|
||||||
|
capture: 'unauthenticatedAttributes'
|
||||||
|
}]
|
||||||
|
};
|
||||||
|
|
||||||
|
p7v.signedDataValidator = {
|
||||||
|
name: 'SignedData',
|
||||||
|
tagClass: asn1.Class.UNIVERSAL,
|
||||||
|
type: asn1.Type.SEQUENCE,
|
||||||
|
constructed: true,
|
||||||
|
value: [{
|
||||||
|
name: 'SignedData.Version',
|
||||||
|
tagClass: asn1.Class.UNIVERSAL,
|
||||||
|
type: asn1.Type.INTEGER,
|
||||||
|
constructed: false,
|
||||||
|
capture: 'version'
|
||||||
|
}, {
|
||||||
|
name: 'SignedData.DigestAlgorithms',
|
||||||
|
tagClass: asn1.Class.UNIVERSAL,
|
||||||
|
type: asn1.Type.SET,
|
||||||
|
constructed: true,
|
||||||
|
captureAsn1: 'digestAlgorithms'
|
||||||
|
},
|
||||||
|
contentInfoValidator,
|
||||||
|
{
|
||||||
|
name: 'SignedData.Certificates',
|
||||||
|
tagClass: asn1.Class.CONTEXT_SPECIFIC,
|
||||||
|
type: 0,
|
||||||
|
optional: true,
|
||||||
|
captureAsn1: 'certificates'
|
||||||
|
}, {
|
||||||
|
name: 'SignedData.CertificateRevocationLists',
|
||||||
|
tagClass: asn1.Class.CONTEXT_SPECIFIC,
|
||||||
|
type: 1,
|
||||||
|
optional: true,
|
||||||
|
captureAsn1: 'crls'
|
||||||
|
}, {
|
||||||
|
name: 'SignedData.SignerInfos',
|
||||||
|
tagClass: asn1.Class.UNIVERSAL,
|
||||||
|
type: asn1.Type.SET,
|
||||||
|
capture: 'signerInfos',
|
||||||
|
optional: true,
|
||||||
|
value: [signerValidator]
|
||||||
|
}]
|
||||||
|
};
|
||||||
|
|
||||||
|
p7v.recipientInfoValidator = {
|
||||||
|
name: 'RecipientInfo',
|
||||||
|
tagClass: asn1.Class.UNIVERSAL,
|
||||||
|
type: asn1.Type.SEQUENCE,
|
||||||
|
constructed: true,
|
||||||
|
value: [{
|
||||||
|
name: 'RecipientInfo.version',
|
||||||
|
tagClass: asn1.Class.UNIVERSAL,
|
||||||
|
type: asn1.Type.INTEGER,
|
||||||
|
constructed: false,
|
||||||
|
capture: 'version'
|
||||||
|
}, {
|
||||||
|
name: 'RecipientInfo.issuerAndSerial',
|
||||||
|
tagClass: asn1.Class.UNIVERSAL,
|
||||||
|
type: asn1.Type.SEQUENCE,
|
||||||
|
constructed: true,
|
||||||
|
value: [{
|
||||||
|
name: 'RecipientInfo.issuerAndSerial.issuer',
|
||||||
|
tagClass: asn1.Class.UNIVERSAL,
|
||||||
|
type: asn1.Type.SEQUENCE,
|
||||||
|
constructed: true,
|
||||||
|
captureAsn1: 'issuer'
|
||||||
|
}, {
|
||||||
|
name: 'RecipientInfo.issuerAndSerial.serialNumber',
|
||||||
|
tagClass: asn1.Class.UNIVERSAL,
|
||||||
|
type: asn1.Type.INTEGER,
|
||||||
|
constructed: false,
|
||||||
|
capture: 'serial'
|
||||||
|
}]
|
||||||
|
}, {
|
||||||
|
name: 'RecipientInfo.keyEncryptionAlgorithm',
|
||||||
|
tagClass: asn1.Class.UNIVERSAL,
|
||||||
|
type: asn1.Type.SEQUENCE,
|
||||||
|
constructed: true,
|
||||||
|
value: [{
|
||||||
|
name: 'RecipientInfo.keyEncryptionAlgorithm.algorithm',
|
||||||
|
tagClass: asn1.Class.UNIVERSAL,
|
||||||
|
type: asn1.Type.OID,
|
||||||
|
constructed: false,
|
||||||
|
capture: 'encAlgorithm'
|
||||||
|
}, {
|
||||||
|
name: 'RecipientInfo.keyEncryptionAlgorithm.parameter',
|
||||||
|
tagClass: asn1.Class.UNIVERSAL,
|
||||||
|
constructed: false,
|
||||||
|
captureAsn1: 'encParameter'
|
||||||
|
}]
|
||||||
|
}, {
|
||||||
|
name: 'RecipientInfo.encryptedKey',
|
||||||
|
tagClass: asn1.Class.UNIVERSAL,
|
||||||
|
type: asn1.Type.OCTETSTRING,
|
||||||
|
constructed: false,
|
||||||
|
capture: 'encKey'
|
||||||
|
}]
|
||||||
|
};
|
||||||
|
|
||||||
|
} // end module implementation
|
||||||
|
|
||||||
|
/* ########## Begin module wrapper ########## */
|
||||||
|
var name = 'pkcs7asn1';
|
||||||
|
if(typeof define !== 'function') {
|
||||||
|
// NodeJS -> AMD
|
||||||
|
if(typeof module === 'object' && module.exports) {
|
||||||
|
var nodeJS = true;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
factory(require, module);
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
// <script>
|
||||||
|
if(typeof forge === 'undefined') {
|
||||||
|
forge = {};
|
||||||
|
}
|
||||||
|
return initModule(forge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// AMD
|
||||||
|
var deps;
|
||||||
|
var defineFunc = function(require, module) {
|
||||||
|
module.exports = function(forge) {
|
||||||
|
var mods = deps.map(function(dep) {
|
||||||
|
return require(dep);
|
||||||
|
}).concat(initModule);
|
||||||
|
// handle circular dependencies
|
||||||
|
forge = forge || {};
|
||||||
|
forge.defined = forge.defined || {};
|
||||||
|
if(forge.defined[name]) {
|
||||||
|
return forge[name];
|
||||||
|
}
|
||||||
|
forge.defined[name] = true;
|
||||||
|
for(var i = 0; i < mods.length; ++i) {
|
||||||
|
mods[i](forge);
|
||||||
|
}
|
||||||
|
return forge[name];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
var tmpDefine = define;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
|
||||||
|
if(nodeJS) {
|
||||||
|
delete define;
|
||||||
|
return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
}
|
||||||
|
define = tmpDefine;
|
||||||
|
return define.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
};
|
||||||
|
define(['require', 'module', './asn1', './util'], function() {
|
||||||
|
defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
});
|
||||||
|
})();
|
||||||
161
forge.js/pki.js
Normal file
@@ -0,0 +1,161 @@
|
|||||||
|
/**
|
||||||
|
* Javascript implementation of a basic Public Key Infrastructure, including
|
||||||
|
* support for RSA public and private keys.
|
||||||
|
*
|
||||||
|
* @author Dave Longley
|
||||||
|
*
|
||||||
|
* Copyright (c) 2010-2013 Digital Bazaar, Inc.
|
||||||
|
*/
|
||||||
|
(function() {
|
||||||
|
/* ########## Begin module implementation ########## */
|
||||||
|
function initModule(forge) {
|
||||||
|
|
||||||
|
// shortcut for asn.1 API
|
||||||
|
var asn1 = forge.asn1;
|
||||||
|
|
||||||
|
/* Public Key Infrastructure (PKI) implementation. */
|
||||||
|
var pki = forge.pki = forge.pki || {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* NOTE: THIS METHOD IS DEPRECATED. Use pem.decode() instead.
|
||||||
|
*
|
||||||
|
* Converts PEM-formatted data to DER.
|
||||||
|
*
|
||||||
|
* @param pem the PEM-formatted data.
|
||||||
|
*
|
||||||
|
* @return the DER-formatted data.
|
||||||
|
*/
|
||||||
|
pki.pemToDer = function(pem) {
|
||||||
|
var msg = forge.pem.decode(pem)[0];
|
||||||
|
if(msg.procType && msg.procType.type === 'ENCRYPTED') {
|
||||||
|
throw new Error('Could not convert PEM to DER; PEM is encrypted.');
|
||||||
|
}
|
||||||
|
return forge.util.createBuffer(msg.body);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts an RSA private key from PEM format.
|
||||||
|
*
|
||||||
|
* @param pem the PEM-formatted private key.
|
||||||
|
*
|
||||||
|
* @return the private key.
|
||||||
|
*/
|
||||||
|
pki.privateKeyFromPem = function(pem) {
|
||||||
|
var msg = forge.pem.decode(pem)[0];
|
||||||
|
|
||||||
|
if(msg.type !== 'PRIVATE KEY' && msg.type !== 'RSA PRIVATE KEY') {
|
||||||
|
var error = new Error('Could not convert private key from PEM; PEM ' +
|
||||||
|
'header type is not "PRIVATE KEY" or "RSA PRIVATE KEY".');
|
||||||
|
error.headerType = msg.type;
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
if(msg.procType && msg.procType.type === 'ENCRYPTED') {
|
||||||
|
throw new Error('Could not convert private key from PEM; PEM is encrypted.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert DER to ASN.1 object
|
||||||
|
var obj = asn1.fromDer(msg.body);
|
||||||
|
|
||||||
|
return pki.privateKeyFromAsn1(obj);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts an RSA private key to PEM format.
|
||||||
|
*
|
||||||
|
* @param key the private key.
|
||||||
|
* @param maxline the maximum characters per line, defaults to 64.
|
||||||
|
*
|
||||||
|
* @return the PEM-formatted private key.
|
||||||
|
*/
|
||||||
|
pki.privateKeyToPem = function(key, maxline) {
|
||||||
|
// convert to ASN.1, then DER, then PEM-encode
|
||||||
|
var msg = {
|
||||||
|
type: 'RSA PRIVATE KEY',
|
||||||
|
body: asn1.toDer(pki.privateKeyToAsn1(key)).getBytes()
|
||||||
|
};
|
||||||
|
return forge.pem.encode(msg, {maxline: maxline});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a PrivateKeyInfo to PEM format.
|
||||||
|
*
|
||||||
|
* @param pki the PrivateKeyInfo.
|
||||||
|
* @param maxline the maximum characters per line, defaults to 64.
|
||||||
|
*
|
||||||
|
* @return the PEM-formatted private key.
|
||||||
|
*/
|
||||||
|
pki.privateKeyInfoToPem = function(pki, maxline) {
|
||||||
|
// convert to DER, then PEM-encode
|
||||||
|
var msg = {
|
||||||
|
type: 'PRIVATE KEY',
|
||||||
|
body: asn1.toDer(pki).getBytes()
|
||||||
|
};
|
||||||
|
return forge.pem.encode(msg, {maxline: maxline});
|
||||||
|
};
|
||||||
|
|
||||||
|
} // end module implementation
|
||||||
|
|
||||||
|
/* ########## Begin module wrapper ########## */
|
||||||
|
var name = 'pki';
|
||||||
|
if(typeof define !== 'function') {
|
||||||
|
// NodeJS -> AMD
|
||||||
|
if(typeof module === 'object' && module.exports) {
|
||||||
|
var nodeJS = true;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
factory(require, module);
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
// <script>
|
||||||
|
if(typeof forge === 'undefined') {
|
||||||
|
forge = {};
|
||||||
|
}
|
||||||
|
return initModule(forge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// AMD
|
||||||
|
var deps;
|
||||||
|
var defineFunc = function(require, module) {
|
||||||
|
module.exports = function(forge) {
|
||||||
|
var mods = deps.map(function(dep) {
|
||||||
|
return require(dep);
|
||||||
|
}).concat(initModule);
|
||||||
|
// handle circular dependencies
|
||||||
|
forge = forge || {};
|
||||||
|
forge.defined = forge.defined || {};
|
||||||
|
if(forge.defined[name]) {
|
||||||
|
return forge[name];
|
||||||
|
}
|
||||||
|
forge.defined[name] = true;
|
||||||
|
for(var i = 0; i < mods.length; ++i) {
|
||||||
|
mods[i](forge);
|
||||||
|
}
|
||||||
|
return forge[name];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
var tmpDefine = define;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
|
||||||
|
if(nodeJS) {
|
||||||
|
delete define;
|
||||||
|
return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
}
|
||||||
|
define = tmpDefine;
|
||||||
|
return define.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
};
|
||||||
|
define([
|
||||||
|
'require',
|
||||||
|
'module',
|
||||||
|
'./asn1',
|
||||||
|
'./oids',
|
||||||
|
'./pbe',
|
||||||
|
'./pem',
|
||||||
|
'./pbkdf2',
|
||||||
|
'./pkcs12',
|
||||||
|
'./pss',
|
||||||
|
'./rsa',
|
||||||
|
'./util',
|
||||||
|
'./x509'
|
||||||
|
], function() {
|
||||||
|
defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
});
|
||||||
|
})();
|
||||||
337
forge.js/prime.js
Normal file
@@ -0,0 +1,337 @@
|
|||||||
|
/**
|
||||||
|
* Prime number generation API.
|
||||||
|
*
|
||||||
|
* @author Dave Longley
|
||||||
|
*
|
||||||
|
* Copyright (c) 2014 Digital Bazaar, Inc.
|
||||||
|
*/
|
||||||
|
(function() {
|
||||||
|
/* ########## Begin module implementation ########## */
|
||||||
|
function initModule(forge) {
|
||||||
|
|
||||||
|
// forge.prime already defined
|
||||||
|
if(forge.prime) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* PRIME API */
|
||||||
|
var prime = forge.prime = forge.prime || {};
|
||||||
|
|
||||||
|
var BigInteger = forge.jsbn.BigInteger;
|
||||||
|
|
||||||
|
// primes are 30k+i for i = 1, 7, 11, 13, 17, 19, 23, 29
|
||||||
|
var GCD_30_DELTA = [6, 4, 2, 4, 2, 4, 6, 2];
|
||||||
|
var THIRTY = new BigInteger(null);
|
||||||
|
THIRTY.fromInt(30);
|
||||||
|
var op_or = function(x, y) {return x|y;};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a random probable prime with the given number of bits.
|
||||||
|
*
|
||||||
|
* Alternative algorithms can be specified by name as a string or as an
|
||||||
|
* object with custom options like so:
|
||||||
|
*
|
||||||
|
* {
|
||||||
|
* name: 'PRIMEINC',
|
||||||
|
* options: {
|
||||||
|
* maxBlockTime: <the maximum amount of time to block the main
|
||||||
|
* thread before allowing I/O other JS to run>,
|
||||||
|
* millerRabinTests: <the number of miller-rabin tests to run>,
|
||||||
|
* workerScript: <the worker script URL>,
|
||||||
|
* workers: <the number of web workers (if supported) to use,
|
||||||
|
* -1 to use estimated cores minus one>.
|
||||||
|
* workLoad: the size of the work load, ie: number of possible prime
|
||||||
|
* numbers for each web worker to check per work assignment,
|
||||||
|
* (default: 100).
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* @param bits the number of bits for the prime number.
|
||||||
|
* @param options the options to use.
|
||||||
|
* [algorithm] the algorithm to use (default: 'PRIMEINC').
|
||||||
|
* [prng] a custom crypto-secure pseudo-random number generator to use,
|
||||||
|
* that must define "getBytesSync".
|
||||||
|
*
|
||||||
|
* @return callback(err, num) called once the operation completes.
|
||||||
|
*/
|
||||||
|
prime.generateProbablePrime = function(bits, options, callback) {
|
||||||
|
if(typeof options === 'function') {
|
||||||
|
callback = options;
|
||||||
|
options = {};
|
||||||
|
}
|
||||||
|
options = options || {};
|
||||||
|
|
||||||
|
// default to PRIMEINC algorithm
|
||||||
|
var algorithm = options.algorithm || 'PRIMEINC';
|
||||||
|
if(typeof algorithm === 'string') {
|
||||||
|
algorithm = {name: algorithm};
|
||||||
|
}
|
||||||
|
algorithm.options = algorithm.options || {};
|
||||||
|
|
||||||
|
// create prng with api that matches BigInteger secure random
|
||||||
|
var prng = options.prng || forge.random;
|
||||||
|
var rng = {
|
||||||
|
// x is an array to fill with bytes
|
||||||
|
nextBytes: function(x) {
|
||||||
|
var b = prng.getBytesSync(x.length);
|
||||||
|
for(var i = 0; i < x.length; ++i) {
|
||||||
|
x[i] = b.charCodeAt(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if(algorithm.name === 'PRIMEINC') {
|
||||||
|
return primeincFindPrime(bits, rng, algorithm.options, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error('Invalid prime generation algorithm: ' + algorithm.name);
|
||||||
|
};
|
||||||
|
|
||||||
|
function primeincFindPrime(bits, rng, options, callback) {
|
||||||
|
if('workers' in options) {
|
||||||
|
return primeincFindPrimeWithWorkers(bits, rng, options, callback);
|
||||||
|
}
|
||||||
|
return primeincFindPrimeWithoutWorkers(bits, rng, options, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
function primeincFindPrimeWithoutWorkers(bits, rng, options, callback) {
|
||||||
|
// initialize random number
|
||||||
|
var num = generateRandom(bits, rng);
|
||||||
|
|
||||||
|
/* Note: All primes are of the form 30k+i for i < 30 and gcd(30, i)=1. The
|
||||||
|
number we are given is always aligned at 30k + 1. Each time the number is
|
||||||
|
determined not to be prime we add to get to the next 'i', eg: if the number
|
||||||
|
was at 30k + 1 we add 6. */
|
||||||
|
var deltaIdx = 0;
|
||||||
|
|
||||||
|
// get required number of MR tests
|
||||||
|
var mrTests = getMillerRabinTests(num.bitLength());
|
||||||
|
if('millerRabinTests' in options) {
|
||||||
|
mrTests = options.millerRabinTests;
|
||||||
|
}
|
||||||
|
|
||||||
|
// find prime nearest to 'num' for maxBlockTime ms
|
||||||
|
// 10 ms gives 5ms of leeway for other calculations before dropping
|
||||||
|
// below 60fps (1000/60 == 16.67), but in reality, the number will
|
||||||
|
// likely be higher due to an 'atomic' big int modPow
|
||||||
|
var maxBlockTime = 10;
|
||||||
|
if('maxBlockTime' in options) {
|
||||||
|
maxBlockTime = options.maxBlockTime;
|
||||||
|
}
|
||||||
|
var start = +new Date();
|
||||||
|
do {
|
||||||
|
// overflow, regenerate random number
|
||||||
|
if(num.bitLength() > bits) {
|
||||||
|
num = generateRandom(bits, rng);
|
||||||
|
}
|
||||||
|
// do primality test
|
||||||
|
if(num.isProbablePrime(mrTests)) {
|
||||||
|
return callback(null, num);
|
||||||
|
}
|
||||||
|
// get next potential prime
|
||||||
|
num.dAddOffset(GCD_30_DELTA[deltaIdx++ % 8], 0);
|
||||||
|
} while(maxBlockTime < 0 || (+new Date() - start < maxBlockTime));
|
||||||
|
|
||||||
|
// keep trying (setImmediate would be better here)
|
||||||
|
forge.util.setImmediate(function() {
|
||||||
|
primeincFindPrimeWithoutWorkers(bits, rng, options, callback);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function primeincFindPrimeWithWorkers(bits, rng, options, callback) {
|
||||||
|
// web workers unavailable
|
||||||
|
if(typeof Worker === 'undefined') {
|
||||||
|
return primeincFindPrimeWithoutWorkers(bits, rng, options, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
// initialize random number
|
||||||
|
var num = generateRandom(bits, rng);
|
||||||
|
|
||||||
|
// use web workers to generate keys
|
||||||
|
var numWorkers = options.workers;
|
||||||
|
var workLoad = options.workLoad || 100;
|
||||||
|
var range = workLoad * 30 / 8;
|
||||||
|
var workerScript = options.workerScript || 'forge/prime.worker.js';
|
||||||
|
if(numWorkers === -1) {
|
||||||
|
return forge.util.estimateCores(function(err, cores) {
|
||||||
|
if(err) {
|
||||||
|
// default to 2
|
||||||
|
cores = 2;
|
||||||
|
}
|
||||||
|
numWorkers = cores - 1;
|
||||||
|
generate();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
generate();
|
||||||
|
|
||||||
|
function generate() {
|
||||||
|
// require at least 1 worker
|
||||||
|
numWorkers = Math.max(1, numWorkers);
|
||||||
|
|
||||||
|
// TODO: consider optimizing by starting workers outside getPrime() ...
|
||||||
|
// note that in order to clean up they will have to be made internally
|
||||||
|
// asynchronous which may actually be slower
|
||||||
|
|
||||||
|
// start workers immediately
|
||||||
|
var workers = [];
|
||||||
|
for(var i = 0; i < numWorkers; ++i) {
|
||||||
|
// FIXME: fix path or use blob URLs
|
||||||
|
workers[i] = new Worker(workerScript);
|
||||||
|
}
|
||||||
|
var running = numWorkers;
|
||||||
|
|
||||||
|
// listen for requests from workers and assign ranges to find prime
|
||||||
|
for(var i = 0; i < numWorkers; ++i) {
|
||||||
|
workers[i].addEventListener('message', workerMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Note: The distribution of random numbers is unknown. Therefore, each
|
||||||
|
web worker is continuously allocated a range of numbers to check for a
|
||||||
|
random number until one is found.
|
||||||
|
|
||||||
|
Every 30 numbers will be checked just 8 times, because prime numbers
|
||||||
|
have the form:
|
||||||
|
|
||||||
|
30k+i, for i < 30 and gcd(30, i)=1 (there are 8 values of i for this)
|
||||||
|
|
||||||
|
Therefore, if we want a web worker to run N checks before asking for
|
||||||
|
a new range of numbers, each range must contain N*30/8 numbers.
|
||||||
|
|
||||||
|
For 100 checks (workLoad), this is a range of 375. */
|
||||||
|
|
||||||
|
var found = false;
|
||||||
|
function workerMessage(e) {
|
||||||
|
// ignore message, prime already found
|
||||||
|
if(found) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
--running;
|
||||||
|
var data = e.data;
|
||||||
|
if(data.found) {
|
||||||
|
// terminate all workers
|
||||||
|
for(var i = 0; i < workers.length; ++i) {
|
||||||
|
workers[i].terminate();
|
||||||
|
}
|
||||||
|
found = true;
|
||||||
|
return callback(null, new BigInteger(data.prime, 16));
|
||||||
|
}
|
||||||
|
|
||||||
|
// overflow, regenerate random number
|
||||||
|
if(num.bitLength() > bits) {
|
||||||
|
num = generateRandom(bits, rng);
|
||||||
|
}
|
||||||
|
|
||||||
|
// assign new range to check
|
||||||
|
var hex = num.toString(16);
|
||||||
|
|
||||||
|
// start prime search
|
||||||
|
e.target.postMessage({
|
||||||
|
hex: hex,
|
||||||
|
workLoad: workLoad
|
||||||
|
});
|
||||||
|
|
||||||
|
num.dAddOffset(range, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a random number using the given number of bits and RNG.
|
||||||
|
*
|
||||||
|
* @param bits the number of bits for the number.
|
||||||
|
* @param rng the random number generator to use.
|
||||||
|
*
|
||||||
|
* @return the random number.
|
||||||
|
*/
|
||||||
|
function generateRandom(bits, rng) {
|
||||||
|
var num = new BigInteger(bits, rng);
|
||||||
|
// force MSB set
|
||||||
|
var bits1 = bits - 1;
|
||||||
|
if(!num.testBit(bits1)) {
|
||||||
|
num.bitwiseTo(BigInteger.ONE.shiftLeft(bits1), op_or, num);
|
||||||
|
}
|
||||||
|
// align number on 30k+1 boundary
|
||||||
|
num.dAddOffset(31 - num.mod(THIRTY).byteValue(), 0);
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the required number of Miller-Rabin tests to generate a
|
||||||
|
* prime with an error probability of (1/2)^80.
|
||||||
|
*
|
||||||
|
* See Handbook of Applied Cryptography Chapter 4, Table 4.4.
|
||||||
|
*
|
||||||
|
* @param bits the bit size.
|
||||||
|
*
|
||||||
|
* @return the required number of iterations.
|
||||||
|
*/
|
||||||
|
function getMillerRabinTests(bits) {
|
||||||
|
if(bits <= 100) return 27;
|
||||||
|
if(bits <= 150) return 18;
|
||||||
|
if(bits <= 200) return 15;
|
||||||
|
if(bits <= 250) return 12;
|
||||||
|
if(bits <= 300) return 9;
|
||||||
|
if(bits <= 350) return 8;
|
||||||
|
if(bits <= 400) return 7;
|
||||||
|
if(bits <= 500) return 6;
|
||||||
|
if(bits <= 600) return 5;
|
||||||
|
if(bits <= 800) return 4;
|
||||||
|
if(bits <= 1250) return 3;
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end module implementation
|
||||||
|
|
||||||
|
/* ########## Begin module wrapper ########## */
|
||||||
|
var name = 'prime';
|
||||||
|
if(typeof define !== 'function') {
|
||||||
|
// NodeJS -> AMD
|
||||||
|
if(typeof module === 'object' && module.exports) {
|
||||||
|
var nodeJS = true;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
factory(require, module);
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
// <script>
|
||||||
|
if(typeof forge === 'undefined') {
|
||||||
|
forge = {};
|
||||||
|
}
|
||||||
|
return initModule(forge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// AMD
|
||||||
|
var deps;
|
||||||
|
var defineFunc = function(require, module) {
|
||||||
|
module.exports = function(forge) {
|
||||||
|
var mods = deps.map(function(dep) {
|
||||||
|
return require(dep);
|
||||||
|
}).concat(initModule);
|
||||||
|
// handle circular dependencies
|
||||||
|
forge = forge || {};
|
||||||
|
forge.defined = forge.defined || {};
|
||||||
|
if(forge.defined[name]) {
|
||||||
|
return forge[name];
|
||||||
|
}
|
||||||
|
forge.defined[name] = true;
|
||||||
|
for(var i = 0; i < mods.length; ++i) {
|
||||||
|
mods[i](forge);
|
||||||
|
}
|
||||||
|
return forge[name];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
var tmpDefine = define;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
|
||||||
|
if(nodeJS) {
|
||||||
|
delete define;
|
||||||
|
return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
}
|
||||||
|
define = tmpDefine;
|
||||||
|
return define.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
};
|
||||||
|
define(['require', 'module', './util', './jsbn', './random'], function() {
|
||||||
|
defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
});
|
||||||
|
|
||||||
|
})();
|
||||||
165
forge.js/prime.worker.js
Normal file
@@ -0,0 +1,165 @@
|
|||||||
|
/**
|
||||||
|
* RSA Key Generation Worker.
|
||||||
|
*
|
||||||
|
* @author Dave Longley
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013 Digital Bazaar, Inc.
|
||||||
|
*/
|
||||||
|
importScripts('jsbn.js');
|
||||||
|
|
||||||
|
// prime constants
|
||||||
|
var LOW_PRIMES = [2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311,313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,409,419,421,431,433,439,443,449,457,461,463,467,479,487,491,499,503,509,521,523,541,547,557,563,569,571,577,587,593,599,601,607,613,617,619,631,641,643,647,653,659,661,673,677,683,691,701,709,719,727,733,739,743,751,757,761,769,773,787,797,809,811,821,823,827,829,839,853,857,859,863,877,881,883,887,907,911,919,929,937,941,947,953,967,971,977,983,991,997];
|
||||||
|
var LP_LIMIT = (1 << 26) / LOW_PRIMES[LOW_PRIMES.length - 1];
|
||||||
|
|
||||||
|
var BigInteger = forge.jsbn.BigInteger;
|
||||||
|
var BIG_TWO = new BigInteger(null);
|
||||||
|
BIG_TWO.fromInt(2);
|
||||||
|
|
||||||
|
self.addEventListener('message', function(e) {
|
||||||
|
var result = findPrime(e.data);
|
||||||
|
self.postMessage(result);
|
||||||
|
});
|
||||||
|
|
||||||
|
// start receiving ranges to check
|
||||||
|
self.postMessage({found: false});
|
||||||
|
|
||||||
|
// primes are 30k+i for i = 1, 7, 11, 13, 17, 19, 23, 29
|
||||||
|
var GCD_30_DELTA = [6, 4, 2, 4, 2, 4, 6, 2];
|
||||||
|
|
||||||
|
function findPrime(data) {
|
||||||
|
// TODO: abstract based on data.algorithm (PRIMEINC vs. others)
|
||||||
|
|
||||||
|
// create BigInteger from given random bytes
|
||||||
|
var num = new BigInteger(data.hex, 16);
|
||||||
|
|
||||||
|
/* Note: All primes are of the form 30k+i for i < 30 and gcd(30, i)=1. The
|
||||||
|
number we are given is always aligned at 30k + 1. Each time the number is
|
||||||
|
determined not to be prime we add to get to the next 'i', eg: if the number
|
||||||
|
was at 30k + 1 we add 6. */
|
||||||
|
var deltaIdx = 0;
|
||||||
|
|
||||||
|
// find nearest prime
|
||||||
|
var workLoad = data.workLoad;
|
||||||
|
for(var i = 0; i < workLoad; ++i) {
|
||||||
|
// do primality test
|
||||||
|
if(isProbablePrime(num)) {
|
||||||
|
return {found: true, prime: num.toString(16)};
|
||||||
|
}
|
||||||
|
// get next potential prime
|
||||||
|
num.dAddOffset(GCD_30_DELTA[deltaIdx++ % 8], 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {found: false};
|
||||||
|
}
|
||||||
|
|
||||||
|
function isProbablePrime(n) {
|
||||||
|
// divide by low primes, ignore even checks, etc (n alread aligned properly)
|
||||||
|
var i = 1;
|
||||||
|
while(i < LOW_PRIMES.length) {
|
||||||
|
var m = LOW_PRIMES[i];
|
||||||
|
var j = i + 1;
|
||||||
|
while(j < LOW_PRIMES.length && m < LP_LIMIT) {
|
||||||
|
m *= LOW_PRIMES[j++];
|
||||||
|
}
|
||||||
|
m = n.modInt(m);
|
||||||
|
while(i < j) {
|
||||||
|
if(m % LOW_PRIMES[i++] === 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return runMillerRabin(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
// HAC 4.24, Miller-Rabin
|
||||||
|
function runMillerRabin(n) {
|
||||||
|
// n1 = n - 1
|
||||||
|
var n1 = n.subtract(BigInteger.ONE);
|
||||||
|
|
||||||
|
// get s and d such that n1 = 2^s * d
|
||||||
|
var s = n1.getLowestSetBit();
|
||||||
|
if(s <= 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
var d = n1.shiftRight(s);
|
||||||
|
|
||||||
|
var k = _getMillerRabinTests(n.bitLength());
|
||||||
|
var prng = getPrng();
|
||||||
|
var a;
|
||||||
|
for(var i = 0; i < k; ++i) {
|
||||||
|
// select witness 'a' at random from between 1 and n - 1
|
||||||
|
do {
|
||||||
|
a = new BigInteger(n.bitLength(), prng);
|
||||||
|
} while(a.compareTo(BigInteger.ONE) <= 0 || a.compareTo(n1) >= 0);
|
||||||
|
|
||||||
|
/* See if 'a' is a composite witness. */
|
||||||
|
|
||||||
|
// x = a^d mod n
|
||||||
|
var x = a.modPow(d, n);
|
||||||
|
|
||||||
|
// probably prime
|
||||||
|
if(x.compareTo(BigInteger.ONE) === 0 || x.compareTo(n1) === 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var j = s;
|
||||||
|
while(--j) {
|
||||||
|
// x = x^2 mod a
|
||||||
|
x = x.modPowInt(2, n);
|
||||||
|
|
||||||
|
// 'n' is composite because no previous x == -1 mod n
|
||||||
|
if(x.compareTo(BigInteger.ONE) === 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// x == -1 mod n, so probably prime
|
||||||
|
if(x.compareTo(n1) === 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 'x' is first_x^(n1/2) and is not +/- 1, so 'n' is not prime
|
||||||
|
if(j === 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get pseudo random number generator
|
||||||
|
function getPrng() {
|
||||||
|
// create prng with api that matches BigInteger secure random
|
||||||
|
return {
|
||||||
|
// x is an array to fill with bytes
|
||||||
|
nextBytes: function(x) {
|
||||||
|
for(var i = 0; i < x.length; ++i) {
|
||||||
|
x[i] = Math.floor(Math.random() * 0xFF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the required number of Miller-Rabin tests to generate a
|
||||||
|
* prime with an error probability of (1/2)^80.
|
||||||
|
*
|
||||||
|
* See Handbook of Applied Cryptography Chapter 4, Table 4.4.
|
||||||
|
*
|
||||||
|
* @param bits the bit size.
|
||||||
|
*
|
||||||
|
* @return the required number of iterations.
|
||||||
|
*/
|
||||||
|
function _getMillerRabinTests(bits) {
|
||||||
|
if(bits <= 100) return 27;
|
||||||
|
if(bits <= 150) return 18;
|
||||||
|
if(bits <= 200) return 15;
|
||||||
|
if(bits <= 250) return 12;
|
||||||
|
if(bits <= 300) return 9;
|
||||||
|
if(bits <= 350) return 8;
|
||||||
|
if(bits <= 400) return 7;
|
||||||
|
if(bits <= 500) return 6;
|
||||||
|
if(bits <= 600) return 5;
|
||||||
|
if(bits <= 800) return 4;
|
||||||
|
if(bits <= 1250) return 3;
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
458
forge.js/prng.js
Normal file
@@ -0,0 +1,458 @@
|
|||||||
|
/**
|
||||||
|
* A javascript implementation of a cryptographically-secure
|
||||||
|
* Pseudo Random Number Generator (PRNG). The Fortuna algorithm is followed
|
||||||
|
* here though the use of SHA-256 is not enforced; when generating an
|
||||||
|
* a PRNG context, the hashing algorithm and block cipher used for
|
||||||
|
* the generator are specified via a plugin.
|
||||||
|
*
|
||||||
|
* @author Dave Longley
|
||||||
|
*
|
||||||
|
* Copyright (c) 2010-2014 Digital Bazaar, Inc.
|
||||||
|
*/
|
||||||
|
(function() {
|
||||||
|
/* ########## Begin module implementation ########## */
|
||||||
|
function initModule(forge) {
|
||||||
|
|
||||||
|
var _nodejs = (
|
||||||
|
typeof process !== 'undefined' && process.versions && process.versions.node);
|
||||||
|
var _crypto = null;
|
||||||
|
if(!forge.disableNativeCode && _nodejs && !process.versions['node-webkit']) {
|
||||||
|
_crypto = require('crypto');
|
||||||
|
}
|
||||||
|
|
||||||
|
/* PRNG API */
|
||||||
|
var prng = forge.prng = forge.prng || {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new PRNG context.
|
||||||
|
*
|
||||||
|
* A PRNG plugin must be passed in that will provide:
|
||||||
|
*
|
||||||
|
* 1. A function that initializes the key and seed of a PRNG context. It
|
||||||
|
* will be given a 16 byte key and a 16 byte seed. Any key expansion
|
||||||
|
* or transformation of the seed from a byte string into an array of
|
||||||
|
* integers (or similar) should be performed.
|
||||||
|
* 2. The cryptographic function used by the generator. It takes a key and
|
||||||
|
* a seed.
|
||||||
|
* 3. A seed increment function. It takes the seed and returns seed + 1.
|
||||||
|
* 4. An api to create a message digest.
|
||||||
|
*
|
||||||
|
* For an example, see random.js.
|
||||||
|
*
|
||||||
|
* @param plugin the PRNG plugin to use.
|
||||||
|
*/
|
||||||
|
prng.create = function(plugin) {
|
||||||
|
var ctx = {
|
||||||
|
plugin: plugin,
|
||||||
|
key: null,
|
||||||
|
seed: null,
|
||||||
|
time: null,
|
||||||
|
// number of reseeds so far
|
||||||
|
reseeds: 0,
|
||||||
|
// amount of data generated so far
|
||||||
|
generated: 0
|
||||||
|
};
|
||||||
|
|
||||||
|
// create 32 entropy pools (each is a message digest)
|
||||||
|
var md = plugin.md;
|
||||||
|
var pools = new Array(32);
|
||||||
|
for(var i = 0; i < 32; ++i) {
|
||||||
|
pools[i] = md.create();
|
||||||
|
}
|
||||||
|
ctx.pools = pools;
|
||||||
|
|
||||||
|
// entropy pools are written to cyclically, starting at index 0
|
||||||
|
ctx.pool = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates random bytes. The bytes may be generated synchronously or
|
||||||
|
* asynchronously. Web workers must use the asynchronous interface or
|
||||||
|
* else the behavior is undefined.
|
||||||
|
*
|
||||||
|
* @param count the number of random bytes to generate.
|
||||||
|
* @param [callback(err, bytes)] called once the operation completes.
|
||||||
|
*
|
||||||
|
* @return count random bytes as a string.
|
||||||
|
*/
|
||||||
|
ctx.generate = function(count, callback) {
|
||||||
|
// do synchronously
|
||||||
|
if(!callback) {
|
||||||
|
return ctx.generateSync(count);
|
||||||
|
}
|
||||||
|
|
||||||
|
// simple generator using counter-based CBC
|
||||||
|
var cipher = ctx.plugin.cipher;
|
||||||
|
var increment = ctx.plugin.increment;
|
||||||
|
var formatKey = ctx.plugin.formatKey;
|
||||||
|
var formatSeed = ctx.plugin.formatSeed;
|
||||||
|
var b = forge.util.createBuffer();
|
||||||
|
|
||||||
|
// reset key for every request
|
||||||
|
ctx.key = null;
|
||||||
|
|
||||||
|
generate();
|
||||||
|
|
||||||
|
function generate(err) {
|
||||||
|
if(err) {
|
||||||
|
return callback(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
// sufficient bytes generated
|
||||||
|
if(b.length() >= count) {
|
||||||
|
return callback(null, b.getBytes(count));
|
||||||
|
}
|
||||||
|
|
||||||
|
// if amount of data generated is greater than 1 MiB, trigger reseed
|
||||||
|
if(ctx.generated > 0xfffff) {
|
||||||
|
ctx.key = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ctx.key === null) {
|
||||||
|
// prevent stack overflow
|
||||||
|
return forge.util.nextTick(function() {
|
||||||
|
_reseed(generate);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// generate the random bytes
|
||||||
|
var bytes = cipher(ctx.key, ctx.seed);
|
||||||
|
ctx.generated += bytes.length;
|
||||||
|
b.putBytes(bytes);
|
||||||
|
|
||||||
|
// generate bytes for a new key and seed
|
||||||
|
ctx.key = formatKey(cipher(ctx.key, increment(ctx.seed)));
|
||||||
|
ctx.seed = formatSeed(cipher(ctx.key, ctx.seed));
|
||||||
|
|
||||||
|
forge.util.setImmediate(generate);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates random bytes synchronously.
|
||||||
|
*
|
||||||
|
* @param count the number of random bytes to generate.
|
||||||
|
*
|
||||||
|
* @return count random bytes as a string.
|
||||||
|
*/
|
||||||
|
ctx.generateSync = function(count) {
|
||||||
|
// simple generator using counter-based CBC
|
||||||
|
var cipher = ctx.plugin.cipher;
|
||||||
|
var increment = ctx.plugin.increment;
|
||||||
|
var formatKey = ctx.plugin.formatKey;
|
||||||
|
var formatSeed = ctx.plugin.formatSeed;
|
||||||
|
|
||||||
|
// reset key for every request
|
||||||
|
ctx.key = null;
|
||||||
|
|
||||||
|
var b = forge.util.createBuffer();
|
||||||
|
while(b.length() < count) {
|
||||||
|
// if amount of data generated is greater than 1 MiB, trigger reseed
|
||||||
|
if(ctx.generated > 0xfffff) {
|
||||||
|
ctx.key = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ctx.key === null) {
|
||||||
|
_reseedSync();
|
||||||
|
}
|
||||||
|
|
||||||
|
// generate the random bytes
|
||||||
|
var bytes = cipher(ctx.key, ctx.seed);
|
||||||
|
ctx.generated += bytes.length;
|
||||||
|
b.putBytes(bytes);
|
||||||
|
|
||||||
|
// generate bytes for a new key and seed
|
||||||
|
ctx.key = formatKey(cipher(ctx.key, increment(ctx.seed)));
|
||||||
|
ctx.seed = formatSeed(cipher(ctx.key, ctx.seed));
|
||||||
|
}
|
||||||
|
|
||||||
|
return b.getBytes(count);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private function that asynchronously reseeds a generator.
|
||||||
|
*
|
||||||
|
* @param callback(err) called once the operation completes.
|
||||||
|
*/
|
||||||
|
function _reseed(callback) {
|
||||||
|
if(ctx.pools[0].messageLength >= 32) {
|
||||||
|
_seed();
|
||||||
|
return callback();
|
||||||
|
}
|
||||||
|
// not enough seed data...
|
||||||
|
var needed = (32 - ctx.pools[0].messageLength) << 5;
|
||||||
|
ctx.seedFile(needed, function(err, bytes) {
|
||||||
|
if(err) {
|
||||||
|
return callback(err);
|
||||||
|
}
|
||||||
|
ctx.collect(bytes);
|
||||||
|
_seed();
|
||||||
|
callback();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private function that synchronously reseeds a generator.
|
||||||
|
*/
|
||||||
|
function _reseedSync() {
|
||||||
|
if(ctx.pools[0].messageLength >= 32) {
|
||||||
|
return _seed();
|
||||||
|
}
|
||||||
|
// not enough seed data...
|
||||||
|
var needed = (32 - ctx.pools[0].messageLength) << 5;
|
||||||
|
ctx.collect(ctx.seedFileSync(needed));
|
||||||
|
_seed();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private function that seeds a generator once enough bytes are available.
|
||||||
|
*/
|
||||||
|
function _seed() {
|
||||||
|
// create a plugin-based message digest
|
||||||
|
var md = ctx.plugin.md.create();
|
||||||
|
|
||||||
|
// digest pool 0's entropy and restart it
|
||||||
|
md.update(ctx.pools[0].digest().getBytes());
|
||||||
|
ctx.pools[0].start();
|
||||||
|
|
||||||
|
// digest the entropy of other pools whose index k meet the
|
||||||
|
// condition '2^k mod n == 0' where n is the number of reseeds
|
||||||
|
var k = 1;
|
||||||
|
for(var i = 1; i < 32; ++i) {
|
||||||
|
// prevent signed numbers from being used
|
||||||
|
k = (k === 31) ? 0x80000000 : (k << 2);
|
||||||
|
if(k % ctx.reseeds === 0) {
|
||||||
|
md.update(ctx.pools[i].digest().getBytes());
|
||||||
|
ctx.pools[i].start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// get digest for key bytes and iterate again for seed bytes
|
||||||
|
var keyBytes = md.digest().getBytes();
|
||||||
|
md.start();
|
||||||
|
md.update(keyBytes);
|
||||||
|
var seedBytes = md.digest().getBytes();
|
||||||
|
|
||||||
|
// update
|
||||||
|
ctx.key = ctx.plugin.formatKey(keyBytes);
|
||||||
|
ctx.seed = ctx.plugin.formatSeed(seedBytes);
|
||||||
|
ctx.reseeds = (ctx.reseeds === 0xffffffff) ? 0 : ctx.reseeds + 1;
|
||||||
|
ctx.generated = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The built-in default seedFile. This seedFile is used when entropy
|
||||||
|
* is needed immediately.
|
||||||
|
*
|
||||||
|
* @param needed the number of bytes that are needed.
|
||||||
|
*
|
||||||
|
* @return the random bytes.
|
||||||
|
*/
|
||||||
|
function defaultSeedFile(needed) {
|
||||||
|
// use window.crypto.getRandomValues strong source of entropy if available
|
||||||
|
var getRandomValues = null;
|
||||||
|
if(typeof window !== 'undefined') {
|
||||||
|
var _crypto = window.crypto || window.msCrypto;
|
||||||
|
if(_crypto && _crypto.getRandomValues) {
|
||||||
|
getRandomValues = function(arr) {
|
||||||
|
return _crypto.getRandomValues(arr);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var b = forge.util.createBuffer();
|
||||||
|
if(getRandomValues) {
|
||||||
|
while(b.length() < needed) {
|
||||||
|
// max byte length is 65536 before QuotaExceededError is thrown
|
||||||
|
// http://www.w3.org/TR/WebCryptoAPI/#RandomSource-method-getRandomValues
|
||||||
|
var count = Math.max(1, Math.min(needed - b.length(), 65536) / 4);
|
||||||
|
var entropy = new Uint32Array(Math.floor(count));
|
||||||
|
try {
|
||||||
|
getRandomValues(entropy);
|
||||||
|
for(var i = 0; i < entropy.length; ++i) {
|
||||||
|
b.putInt32(entropy[i]);
|
||||||
|
}
|
||||||
|
} catch(e) {
|
||||||
|
/* only ignore QuotaExceededError */
|
||||||
|
if(!(typeof QuotaExceededError !== 'undefined' &&
|
||||||
|
e instanceof QuotaExceededError)) {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// be sad and add some weak random data
|
||||||
|
if(b.length() < needed) {
|
||||||
|
/* Draws from Park-Miller "minimal standard" 31 bit PRNG,
|
||||||
|
implemented with David G. Carta's optimization: with 32 bit math
|
||||||
|
and without division (Public Domain). */
|
||||||
|
var hi, lo, next;
|
||||||
|
var seed = Math.floor(Math.random() * 0x010000);
|
||||||
|
while(b.length() < needed) {
|
||||||
|
lo = 16807 * (seed & 0xFFFF);
|
||||||
|
hi = 16807 * (seed >> 16);
|
||||||
|
lo += (hi & 0x7FFF) << 16;
|
||||||
|
lo += hi >> 15;
|
||||||
|
lo = (lo & 0x7FFFFFFF) + (lo >> 31);
|
||||||
|
seed = lo & 0xFFFFFFFF;
|
||||||
|
|
||||||
|
// consume lower 3 bytes of seed
|
||||||
|
for(var i = 0; i < 3; ++i) {
|
||||||
|
// throw in more pseudo random
|
||||||
|
next = seed >>> (i << 3);
|
||||||
|
next ^= Math.floor(Math.random() * 0x0100);
|
||||||
|
b.putByte(String.fromCharCode(next & 0xFF));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return b.getBytes(needed);
|
||||||
|
}
|
||||||
|
// initialize seed file APIs
|
||||||
|
if(_crypto) {
|
||||||
|
// use nodejs async API
|
||||||
|
ctx.seedFile = function(needed, callback) {
|
||||||
|
_crypto.randomBytes(needed, function(err, bytes) {
|
||||||
|
if(err) {
|
||||||
|
return callback(err);
|
||||||
|
}
|
||||||
|
callback(null, bytes.toString());
|
||||||
|
});
|
||||||
|
};
|
||||||
|
// use nodejs sync API
|
||||||
|
ctx.seedFileSync = function(needed) {
|
||||||
|
return _crypto.randomBytes(needed).toString();
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
ctx.seedFile = function(needed, callback) {
|
||||||
|
try {
|
||||||
|
callback(null, defaultSeedFile(needed));
|
||||||
|
} catch(e) {
|
||||||
|
callback(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
ctx.seedFileSync = defaultSeedFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds entropy to a prng ctx's accumulator.
|
||||||
|
*
|
||||||
|
* @param bytes the bytes of entropy as a string.
|
||||||
|
*/
|
||||||
|
ctx.collect = function(bytes) {
|
||||||
|
// iterate over pools distributing entropy cyclically
|
||||||
|
var count = bytes.length;
|
||||||
|
for(var i = 0; i < count; ++i) {
|
||||||
|
ctx.pools[ctx.pool].update(bytes.substr(i, 1));
|
||||||
|
ctx.pool = (ctx.pool === 31) ? 0 : ctx.pool + 1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collects an integer of n bits.
|
||||||
|
*
|
||||||
|
* @param i the integer entropy.
|
||||||
|
* @param n the number of bits in the integer.
|
||||||
|
*/
|
||||||
|
ctx.collectInt = function(i, n) {
|
||||||
|
var bytes = '';
|
||||||
|
for(var x = 0; x < n; x += 8) {
|
||||||
|
bytes += String.fromCharCode((i >> x) & 0xFF);
|
||||||
|
}
|
||||||
|
ctx.collect(bytes);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a Web Worker to receive immediate entropy from the main thread.
|
||||||
|
* This method is required until Web Workers can access the native crypto
|
||||||
|
* API. This method should be called twice for each created worker, once in
|
||||||
|
* the main thread, and once in the worker itself.
|
||||||
|
*
|
||||||
|
* @param worker the worker to register.
|
||||||
|
*/
|
||||||
|
ctx.registerWorker = function(worker) {
|
||||||
|
// worker receives random bytes
|
||||||
|
if(worker === self) {
|
||||||
|
ctx.seedFile = function(needed, callback) {
|
||||||
|
function listener(e) {
|
||||||
|
var data = e.data;
|
||||||
|
if(data.forge && data.forge.prng) {
|
||||||
|
self.removeEventListener('message', listener);
|
||||||
|
callback(data.forge.prng.err, data.forge.prng.bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.addEventListener('message', listener);
|
||||||
|
self.postMessage({forge: {prng: {needed: needed}}});
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
// main thread sends random bytes upon request
|
||||||
|
var listener = function(e) {
|
||||||
|
var data = e.data;
|
||||||
|
if(data.forge && data.forge.prng) {
|
||||||
|
ctx.seedFile(data.forge.prng.needed, function(err, bytes) {
|
||||||
|
worker.postMessage({forge: {prng: {err: err, bytes: bytes}}});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// TODO: do we need to remove the event listener when the worker dies?
|
||||||
|
worker.addEventListener('message', listener);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return ctx;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // end module implementation
|
||||||
|
|
||||||
|
/* ########## Begin module wrapper ########## */
|
||||||
|
var name = 'prng';
|
||||||
|
if(typeof define !== 'function') {
|
||||||
|
// NodeJS -> AMD
|
||||||
|
if(typeof module === 'object' && module.exports) {
|
||||||
|
var nodeJS = true;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
factory(require, module);
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
// <script>
|
||||||
|
if(typeof forge === 'undefined') {
|
||||||
|
forge = {};
|
||||||
|
}
|
||||||
|
return initModule(forge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// AMD
|
||||||
|
var deps;
|
||||||
|
var defineFunc = function(require, module) {
|
||||||
|
module.exports = function(forge) {
|
||||||
|
var mods = deps.map(function(dep) {
|
||||||
|
return require(dep);
|
||||||
|
}).concat(initModule);
|
||||||
|
// handle circular dependencies
|
||||||
|
forge = forge || {};
|
||||||
|
forge.defined = forge.defined || {};
|
||||||
|
if(forge.defined[name]) {
|
||||||
|
return forge[name];
|
||||||
|
}
|
||||||
|
forge.defined[name] = true;
|
||||||
|
for(var i = 0; i < mods.length; ++i) {
|
||||||
|
mods[i](forge);
|
||||||
|
}
|
||||||
|
return forge[name];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
var tmpDefine = define;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
|
||||||
|
if(nodeJS) {
|
||||||
|
delete define;
|
||||||
|
return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
}
|
||||||
|
define = tmpDefine;
|
||||||
|
return define.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
};
|
||||||
|
define(['require', 'module', './md', './util'], function() {
|
||||||
|
defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
});
|
||||||
|
|
||||||
|
})();
|
||||||
295
forge.js/pss.js
Normal file
@@ -0,0 +1,295 @@
|
|||||||
|
/**
|
||||||
|
* Javascript implementation of PKCS#1 PSS signature padding.
|
||||||
|
*
|
||||||
|
* @author Stefan Siegl
|
||||||
|
*
|
||||||
|
* Copyright (c) 2012 Stefan Siegl <stesie@brokenpipe.de>
|
||||||
|
*/
|
||||||
|
(function() {
|
||||||
|
/* ########## Begin module implementation ########## */
|
||||||
|
function initModule(forge) {
|
||||||
|
|
||||||
|
// shortcut for PSS API
|
||||||
|
var pss = forge.pss = forge.pss || {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a PSS signature scheme object.
|
||||||
|
*
|
||||||
|
* There are several ways to provide a salt for encoding:
|
||||||
|
*
|
||||||
|
* 1. Specify the saltLength only and the built-in PRNG will generate it.
|
||||||
|
* 2. Specify the saltLength and a custom PRNG with 'getBytesSync' defined that
|
||||||
|
* will be used.
|
||||||
|
* 3. Specify the salt itself as a forge.util.ByteBuffer.
|
||||||
|
*
|
||||||
|
* @param options the options to use:
|
||||||
|
* md the message digest object to use, a forge md instance.
|
||||||
|
* mgf the mask generation function to use, a forge mgf instance.
|
||||||
|
* [saltLength] the length of the salt in octets.
|
||||||
|
* [prng] the pseudo-random number generator to use to produce a salt.
|
||||||
|
* [salt] the salt to use when encoding.
|
||||||
|
*
|
||||||
|
* @return a signature scheme object.
|
||||||
|
*/
|
||||||
|
pss.create = function(options) {
|
||||||
|
// backwards compatibility w/legacy args: hash, mgf, sLen
|
||||||
|
if(arguments.length === 3) {
|
||||||
|
options = {
|
||||||
|
md: arguments[0],
|
||||||
|
mgf: arguments[1],
|
||||||
|
saltLength: arguments[2]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
var hash = options.md;
|
||||||
|
var mgf = options.mgf;
|
||||||
|
var hLen = hash.digestLength;
|
||||||
|
|
||||||
|
var salt_ = options.salt || null;
|
||||||
|
if(typeof salt_ === 'string') {
|
||||||
|
// assume binary-encoded string
|
||||||
|
salt_ = forge.util.createBuffer(salt_);
|
||||||
|
}
|
||||||
|
|
||||||
|
var sLen;
|
||||||
|
if('saltLength' in options) {
|
||||||
|
sLen = options.saltLength;
|
||||||
|
} else if(salt_ !== null) {
|
||||||
|
sLen = salt_.length();
|
||||||
|
} else {
|
||||||
|
throw new Error('Salt length not specified or specific salt not given.');
|
||||||
|
}
|
||||||
|
|
||||||
|
if(salt_ !== null && salt_.length() !== sLen) {
|
||||||
|
throw new Error('Given salt length does not match length of given salt.');
|
||||||
|
}
|
||||||
|
|
||||||
|
var prng = options.prng || forge.random;
|
||||||
|
|
||||||
|
var pssobj = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encodes a PSS signature.
|
||||||
|
*
|
||||||
|
* This function implements EMSA-PSS-ENCODE as per RFC 3447, section 9.1.1.
|
||||||
|
*
|
||||||
|
* @param md the message digest object with the hash to sign.
|
||||||
|
* @param modsBits the length of the RSA modulus in bits.
|
||||||
|
*
|
||||||
|
* @return the encoded message as a binary-encoded string of length
|
||||||
|
* ceil((modBits - 1) / 8).
|
||||||
|
*/
|
||||||
|
pssobj.encode = function(md, modBits) {
|
||||||
|
var i;
|
||||||
|
var emBits = modBits - 1;
|
||||||
|
var emLen = Math.ceil(emBits / 8);
|
||||||
|
|
||||||
|
/* 2. Let mHash = Hash(M), an octet string of length hLen. */
|
||||||
|
var mHash = md.digest().getBytes();
|
||||||
|
|
||||||
|
/* 3. If emLen < hLen + sLen + 2, output "encoding error" and stop. */
|
||||||
|
if(emLen < hLen + sLen + 2) {
|
||||||
|
throw new Error('Message is too long to encrypt.');
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 4. Generate a random octet string salt of length sLen; if sLen = 0,
|
||||||
|
* then salt is the empty string. */
|
||||||
|
var salt;
|
||||||
|
if(salt_ === null) {
|
||||||
|
salt = prng.getBytesSync(sLen);
|
||||||
|
} else {
|
||||||
|
salt = salt_.bytes();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 5. Let M' = (0x)00 00 00 00 00 00 00 00 || mHash || salt; */
|
||||||
|
var m_ = new forge.util.ByteBuffer();
|
||||||
|
m_.fillWithByte(0, 8);
|
||||||
|
m_.putBytes(mHash);
|
||||||
|
m_.putBytes(salt);
|
||||||
|
|
||||||
|
/* 6. Let H = Hash(M'), an octet string of length hLen. */
|
||||||
|
hash.start();
|
||||||
|
hash.update(m_.getBytes());
|
||||||
|
var h = hash.digest().getBytes();
|
||||||
|
|
||||||
|
/* 7. Generate an octet string PS consisting of emLen - sLen - hLen - 2
|
||||||
|
* zero octets. The length of PS may be 0. */
|
||||||
|
var ps = new forge.util.ByteBuffer();
|
||||||
|
ps.fillWithByte(0, emLen - sLen - hLen - 2);
|
||||||
|
|
||||||
|
/* 8. Let DB = PS || 0x01 || salt; DB is an octet string of length
|
||||||
|
* emLen - hLen - 1. */
|
||||||
|
ps.putByte(0x01);
|
||||||
|
ps.putBytes(salt);
|
||||||
|
var db = ps.getBytes();
|
||||||
|
|
||||||
|
/* 9. Let dbMask = MGF(H, emLen - hLen - 1). */
|
||||||
|
var maskLen = emLen - hLen - 1;
|
||||||
|
var dbMask = mgf.generate(h, maskLen);
|
||||||
|
|
||||||
|
/* 10. Let maskedDB = DB \xor dbMask. */
|
||||||
|
var maskedDB = '';
|
||||||
|
for(i = 0; i < maskLen; i ++) {
|
||||||
|
maskedDB += String.fromCharCode(db.charCodeAt(i) ^ dbMask.charCodeAt(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 11. Set the leftmost 8emLen - emBits bits of the leftmost octet in
|
||||||
|
* maskedDB to zero. */
|
||||||
|
var mask = (0xFF00 >> (8 * emLen - emBits)) & 0xFF;
|
||||||
|
maskedDB = String.fromCharCode(maskedDB.charCodeAt(0) & ~mask) +
|
||||||
|
maskedDB.substr(1);
|
||||||
|
|
||||||
|
/* 12. Let EM = maskedDB || H || 0xbc.
|
||||||
|
* 13. Output EM. */
|
||||||
|
return maskedDB + h + String.fromCharCode(0xbc);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verifies a PSS signature.
|
||||||
|
*
|
||||||
|
* This function implements EMSA-PSS-VERIFY as per RFC 3447, section 9.1.2.
|
||||||
|
*
|
||||||
|
* @param mHash the message digest hash, as a binary-encoded string, to
|
||||||
|
* compare against the signature.
|
||||||
|
* @param em the encoded message, as a binary-encoded string
|
||||||
|
* (RSA decryption result).
|
||||||
|
* @param modsBits the length of the RSA modulus in bits.
|
||||||
|
*
|
||||||
|
* @return true if the signature was verified, false if not.
|
||||||
|
*/
|
||||||
|
pssobj.verify = function(mHash, em, modBits) {
|
||||||
|
var i;
|
||||||
|
var emBits = modBits - 1;
|
||||||
|
var emLen = Math.ceil(emBits / 8);
|
||||||
|
|
||||||
|
/* c. Convert the message representative m to an encoded message EM
|
||||||
|
* of length emLen = ceil((modBits - 1) / 8) octets, where modBits
|
||||||
|
* is the length in bits of the RSA modulus n */
|
||||||
|
em = em.substr(-emLen);
|
||||||
|
|
||||||
|
/* 3. If emLen < hLen + sLen + 2, output "inconsistent" and stop. */
|
||||||
|
if(emLen < hLen + sLen + 2) {
|
||||||
|
throw new Error('Inconsistent parameters to PSS signature verification.');
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 4. If the rightmost octet of EM does not have hexadecimal value
|
||||||
|
* 0xbc, output "inconsistent" and stop. */
|
||||||
|
if(em.charCodeAt(emLen - 1) !== 0xbc) {
|
||||||
|
throw new Error('Encoded message does not end in 0xBC.');
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 5. Let maskedDB be the leftmost emLen - hLen - 1 octets of EM, and
|
||||||
|
* let H be the next hLen octets. */
|
||||||
|
var maskLen = emLen - hLen - 1;
|
||||||
|
var maskedDB = em.substr(0, maskLen);
|
||||||
|
var h = em.substr(maskLen, hLen);
|
||||||
|
|
||||||
|
/* 6. If the leftmost 8emLen - emBits bits of the leftmost octet in
|
||||||
|
* maskedDB are not all equal to zero, output "inconsistent" and stop. */
|
||||||
|
var mask = (0xFF00 >> (8 * emLen - emBits)) & 0xFF;
|
||||||
|
if((maskedDB.charCodeAt(0) & mask) !== 0) {
|
||||||
|
throw new Error('Bits beyond keysize not zero as expected.');
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 7. Let dbMask = MGF(H, emLen - hLen - 1). */
|
||||||
|
var dbMask = mgf.generate(h, maskLen);
|
||||||
|
|
||||||
|
/* 8. Let DB = maskedDB \xor dbMask. */
|
||||||
|
var db = '';
|
||||||
|
for(i = 0; i < maskLen; i ++) {
|
||||||
|
db += String.fromCharCode(maskedDB.charCodeAt(i) ^ dbMask.charCodeAt(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 9. Set the leftmost 8emLen - emBits bits of the leftmost octet
|
||||||
|
* in DB to zero. */
|
||||||
|
db = String.fromCharCode(db.charCodeAt(0) & ~mask) + db.substr(1);
|
||||||
|
|
||||||
|
/* 10. If the emLen - hLen - sLen - 2 leftmost octets of DB are not zero
|
||||||
|
* or if the octet at position emLen - hLen - sLen - 1 (the leftmost
|
||||||
|
* position is "position 1") does not have hexadecimal value 0x01,
|
||||||
|
* output "inconsistent" and stop. */
|
||||||
|
var checkLen = emLen - hLen - sLen - 2;
|
||||||
|
for(i = 0; i < checkLen; i ++) {
|
||||||
|
if(db.charCodeAt(i) !== 0x00) {
|
||||||
|
throw new Error('Leftmost octets not zero as expected');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(db.charCodeAt(checkLen) !== 0x01) {
|
||||||
|
throw new Error('Inconsistent PSS signature, 0x01 marker not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 11. Let salt be the last sLen octets of DB. */
|
||||||
|
var salt = db.substr(-sLen);
|
||||||
|
|
||||||
|
/* 12. Let M' = (0x)00 00 00 00 00 00 00 00 || mHash || salt */
|
||||||
|
var m_ = new forge.util.ByteBuffer();
|
||||||
|
m_.fillWithByte(0, 8);
|
||||||
|
m_.putBytes(mHash);
|
||||||
|
m_.putBytes(salt);
|
||||||
|
|
||||||
|
/* 13. Let H' = Hash(M'), an octet string of length hLen. */
|
||||||
|
hash.start();
|
||||||
|
hash.update(m_.getBytes());
|
||||||
|
var h_ = hash.digest().getBytes();
|
||||||
|
|
||||||
|
/* 14. If H = H', output "consistent." Otherwise, output "inconsistent." */
|
||||||
|
return h === h_;
|
||||||
|
};
|
||||||
|
|
||||||
|
return pssobj;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // end module implementation
|
||||||
|
|
||||||
|
/* ########## Begin module wrapper ########## */
|
||||||
|
var name = 'pss';
|
||||||
|
if(typeof define !== 'function') {
|
||||||
|
// NodeJS -> AMD
|
||||||
|
if(typeof module === 'object' && module.exports) {
|
||||||
|
var nodeJS = true;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
factory(require, module);
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
// <script>
|
||||||
|
if(typeof forge === 'undefined') {
|
||||||
|
forge = {};
|
||||||
|
}
|
||||||
|
return initModule(forge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// AMD
|
||||||
|
var deps;
|
||||||
|
var defineFunc = function(require, module) {
|
||||||
|
module.exports = function(forge) {
|
||||||
|
var mods = deps.map(function(dep) {
|
||||||
|
return require(dep);
|
||||||
|
}).concat(initModule);
|
||||||
|
// handle circular dependencies
|
||||||
|
forge = forge || {};
|
||||||
|
forge.defined = forge.defined || {};
|
||||||
|
if(forge.defined[name]) {
|
||||||
|
return forge[name];
|
||||||
|
}
|
||||||
|
forge.defined[name] = true;
|
||||||
|
for(var i = 0; i < mods.length; ++i) {
|
||||||
|
mods[i](forge);
|
||||||
|
}
|
||||||
|
return forge[name];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
var tmpDefine = define;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
|
||||||
|
if(nodeJS) {
|
||||||
|
delete define;
|
||||||
|
return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
}
|
||||||
|
define = tmpDefine;
|
||||||
|
return define.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
};
|
||||||
|
define(['require', 'module', './random', './util'], function() {
|
||||||
|
defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
});
|
||||||
|
})();
|
||||||
237
forge.js/random.js
Normal file
@@ -0,0 +1,237 @@
|
|||||||
|
/**
|
||||||
|
* An API for getting cryptographically-secure random bytes. The bytes are
|
||||||
|
* generated using the Fortuna algorithm devised by Bruce Schneier and
|
||||||
|
* Niels Ferguson.
|
||||||
|
*
|
||||||
|
* Getting strong random bytes is not yet easy to do in javascript. The only
|
||||||
|
* truish random entropy that can be collected is from the mouse, keyboard, or
|
||||||
|
* from timing with respect to page loads, etc. This generator makes a poor
|
||||||
|
* attempt at providing random bytes when those sources haven't yet provided
|
||||||
|
* enough entropy to initially seed or to reseed the PRNG.
|
||||||
|
*
|
||||||
|
* @author Dave Longley
|
||||||
|
*
|
||||||
|
* Copyright (c) 2009-2014 Digital Bazaar, Inc.
|
||||||
|
*/
|
||||||
|
(function() {
|
||||||
|
/* ########## Begin module implementation ########## */
|
||||||
|
function initModule(forge) {
|
||||||
|
|
||||||
|
// forge.random already defined
|
||||||
|
if(forge.random && forge.random.getBytes) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
(function(jQuery) {
|
||||||
|
|
||||||
|
// the default prng plugin, uses AES-128
|
||||||
|
var prng_aes = {};
|
||||||
|
var _prng_aes_output = new Array(4);
|
||||||
|
var _prng_aes_buffer = forge.util.createBuffer();
|
||||||
|
prng_aes.formatKey = function(key) {
|
||||||
|
// convert the key into 32-bit integers
|
||||||
|
var tmp = forge.util.createBuffer(key);
|
||||||
|
key = new Array(4);
|
||||||
|
key[0] = tmp.getInt32();
|
||||||
|
key[1] = tmp.getInt32();
|
||||||
|
key[2] = tmp.getInt32();
|
||||||
|
key[3] = tmp.getInt32();
|
||||||
|
|
||||||
|
// return the expanded key
|
||||||
|
return forge.aes._expandKey(key, false);
|
||||||
|
};
|
||||||
|
prng_aes.formatSeed = function(seed) {
|
||||||
|
// convert seed into 32-bit integers
|
||||||
|
var tmp = forge.util.createBuffer(seed);
|
||||||
|
seed = new Array(4);
|
||||||
|
seed[0] = tmp.getInt32();
|
||||||
|
seed[1] = tmp.getInt32();
|
||||||
|
seed[2] = tmp.getInt32();
|
||||||
|
seed[3] = tmp.getInt32();
|
||||||
|
return seed;
|
||||||
|
};
|
||||||
|
prng_aes.cipher = function(key, seed) {
|
||||||
|
forge.aes._updateBlock(key, seed, _prng_aes_output, false);
|
||||||
|
_prng_aes_buffer.putInt32(_prng_aes_output[0]);
|
||||||
|
_prng_aes_buffer.putInt32(_prng_aes_output[1]);
|
||||||
|
_prng_aes_buffer.putInt32(_prng_aes_output[2]);
|
||||||
|
_prng_aes_buffer.putInt32(_prng_aes_output[3]);
|
||||||
|
return _prng_aes_buffer.getBytes();
|
||||||
|
};
|
||||||
|
prng_aes.increment = function(seed) {
|
||||||
|
// FIXME: do we care about carry or signed issues?
|
||||||
|
++seed[3];
|
||||||
|
return seed;
|
||||||
|
};
|
||||||
|
prng_aes.md = forge.md.sha256;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new PRNG.
|
||||||
|
*/
|
||||||
|
function spawnPrng() {
|
||||||
|
var ctx = forge.prng.create(prng_aes);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets random bytes. If a native secure crypto API is unavailable, this
|
||||||
|
* method tries to make the bytes more unpredictable by drawing from data that
|
||||||
|
* can be collected from the user of the browser, eg: mouse movement.
|
||||||
|
*
|
||||||
|
* If a callback is given, this method will be called asynchronously.
|
||||||
|
*
|
||||||
|
* @param count the number of random bytes to get.
|
||||||
|
* @param [callback(err, bytes)] called once the operation completes.
|
||||||
|
*
|
||||||
|
* @return the random bytes in a string.
|
||||||
|
*/
|
||||||
|
ctx.getBytes = function(count, callback) {
|
||||||
|
return ctx.generate(count, callback);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets random bytes asynchronously. If a native secure crypto API is
|
||||||
|
* unavailable, this method tries to make the bytes more unpredictable by
|
||||||
|
* drawing from data that can be collected from the user of the browser,
|
||||||
|
* eg: mouse movement.
|
||||||
|
*
|
||||||
|
* @param count the number of random bytes to get.
|
||||||
|
*
|
||||||
|
* @return the random bytes in a string.
|
||||||
|
*/
|
||||||
|
ctx.getBytesSync = function(count) {
|
||||||
|
return ctx.generate(count);
|
||||||
|
};
|
||||||
|
|
||||||
|
return ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
// create default prng context
|
||||||
|
var _ctx = spawnPrng();
|
||||||
|
|
||||||
|
// add other sources of entropy only if window.crypto.getRandomValues is not
|
||||||
|
// available -- otherwise this source will be automatically used by the prng
|
||||||
|
var _nodejs = (
|
||||||
|
typeof process !== 'undefined' && process.versions && process.versions.node);
|
||||||
|
var getRandomValues = null;
|
||||||
|
if(typeof window !== 'undefined') {
|
||||||
|
var _crypto = window.crypto || window.msCrypto;
|
||||||
|
if(_crypto && _crypto.getRandomValues) {
|
||||||
|
getRandomValues = function(arr) {
|
||||||
|
return _crypto.getRandomValues(arr);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(forge.disableNativeCode || (!_nodejs && !getRandomValues)) {
|
||||||
|
// if this is a web worker, do not use weak entropy, instead register to
|
||||||
|
// receive strong entropy asynchronously from the main thread
|
||||||
|
if(typeof window === 'undefined' || window.document === undefined) {
|
||||||
|
// FIXME:
|
||||||
|
}
|
||||||
|
|
||||||
|
// get load time entropy
|
||||||
|
_ctx.collectInt(+new Date(), 32);
|
||||||
|
|
||||||
|
// add some entropy from navigator object
|
||||||
|
if(typeof(navigator) !== 'undefined') {
|
||||||
|
var _navBytes = '';
|
||||||
|
for(var key in navigator) {
|
||||||
|
try {
|
||||||
|
if(typeof(navigator[key]) == 'string') {
|
||||||
|
_navBytes += navigator[key];
|
||||||
|
}
|
||||||
|
} catch(e) {
|
||||||
|
/* Some navigator keys might not be accessible, e.g. the geolocation
|
||||||
|
attribute throws an exception if touched in Mozilla chrome://
|
||||||
|
context.
|
||||||
|
|
||||||
|
Silently ignore this and just don't use this as a source of
|
||||||
|
entropy. */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ctx.collect(_navBytes);
|
||||||
|
_navBytes = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// add mouse and keyboard collectors if jquery is available
|
||||||
|
if(jQuery) {
|
||||||
|
// set up mouse entropy capture
|
||||||
|
jQuery().mousemove(function(e) {
|
||||||
|
// add mouse coords
|
||||||
|
_ctx.collectInt(e.clientX, 16);
|
||||||
|
_ctx.collectInt(e.clientY, 16);
|
||||||
|
});
|
||||||
|
|
||||||
|
// set up keyboard entropy capture
|
||||||
|
jQuery().keypress(function(e) {
|
||||||
|
_ctx.collectInt(e.charCode, 8);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Random API */
|
||||||
|
if(!forge.random) {
|
||||||
|
forge.random = _ctx;
|
||||||
|
} else {
|
||||||
|
// extend forge.random with _ctx
|
||||||
|
for(var key in _ctx) {
|
||||||
|
forge.random[key] = _ctx[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// expose spawn PRNG
|
||||||
|
forge.random.createInstance = spawnPrng;
|
||||||
|
|
||||||
|
})(typeof(jQuery) !== 'undefined' ? jQuery : null);
|
||||||
|
|
||||||
|
} // end module implementation
|
||||||
|
|
||||||
|
/* ########## Begin module wrapper ########## */
|
||||||
|
var name = 'random';
|
||||||
|
if(typeof define !== 'function') {
|
||||||
|
// NodeJS -> AMD
|
||||||
|
if(typeof module === 'object' && module.exports) {
|
||||||
|
var nodeJS = true;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
factory(require, module);
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
// <script>
|
||||||
|
if(typeof forge === 'undefined') {
|
||||||
|
forge = {};
|
||||||
|
}
|
||||||
|
return initModule(forge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// AMD
|
||||||
|
var deps;
|
||||||
|
var defineFunc = function(require, module) {
|
||||||
|
module.exports = function(forge) {
|
||||||
|
var mods = deps.map(function(dep) {
|
||||||
|
return require(dep);
|
||||||
|
}).concat(initModule);
|
||||||
|
// handle circular dependencies
|
||||||
|
forge = forge || {};
|
||||||
|
forge.defined = forge.defined || {};
|
||||||
|
if(forge.defined[name]) {
|
||||||
|
return forge[name];
|
||||||
|
}
|
||||||
|
forge.defined[name] = true;
|
||||||
|
for(var i = 0; i < mods.length; ++i) {
|
||||||
|
mods[i](forge);
|
||||||
|
}
|
||||||
|
return forge[name];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
var tmpDefine = define;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
|
||||||
|
if(nodeJS) {
|
||||||
|
delete define;
|
||||||
|
return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
}
|
||||||
|
define = tmpDefine;
|
||||||
|
return define.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
};
|
||||||
|
define(['require', 'module', './aes', './md', './prng', './util'], function() {
|
||||||
|
defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
});
|
||||||
|
})();
|
||||||
470
forge.js/rc2.js
Normal file
@@ -0,0 +1,470 @@
|
|||||||
|
/**
|
||||||
|
* RC2 implementation.
|
||||||
|
*
|
||||||
|
* @author Stefan Siegl
|
||||||
|
*
|
||||||
|
* Copyright (c) 2012 Stefan Siegl <stesie@brokenpipe.de>
|
||||||
|
*
|
||||||
|
* Information on the RC2 cipher is available from RFC #2268,
|
||||||
|
* http://www.ietf.org/rfc/rfc2268.txt
|
||||||
|
*/
|
||||||
|
(function() {
|
||||||
|
/* ########## Begin module implementation ########## */
|
||||||
|
function initModule(forge) {
|
||||||
|
|
||||||
|
var piTable = [
|
||||||
|
0xd9, 0x78, 0xf9, 0xc4, 0x19, 0xdd, 0xb5, 0xed, 0x28, 0xe9, 0xfd, 0x79, 0x4a, 0xa0, 0xd8, 0x9d,
|
||||||
|
0xc6, 0x7e, 0x37, 0x83, 0x2b, 0x76, 0x53, 0x8e, 0x62, 0x4c, 0x64, 0x88, 0x44, 0x8b, 0xfb, 0xa2,
|
||||||
|
0x17, 0x9a, 0x59, 0xf5, 0x87, 0xb3, 0x4f, 0x13, 0x61, 0x45, 0x6d, 0x8d, 0x09, 0x81, 0x7d, 0x32,
|
||||||
|
0xbd, 0x8f, 0x40, 0xeb, 0x86, 0xb7, 0x7b, 0x0b, 0xf0, 0x95, 0x21, 0x22, 0x5c, 0x6b, 0x4e, 0x82,
|
||||||
|
0x54, 0xd6, 0x65, 0x93, 0xce, 0x60, 0xb2, 0x1c, 0x73, 0x56, 0xc0, 0x14, 0xa7, 0x8c, 0xf1, 0xdc,
|
||||||
|
0x12, 0x75, 0xca, 0x1f, 0x3b, 0xbe, 0xe4, 0xd1, 0x42, 0x3d, 0xd4, 0x30, 0xa3, 0x3c, 0xb6, 0x26,
|
||||||
|
0x6f, 0xbf, 0x0e, 0xda, 0x46, 0x69, 0x07, 0x57, 0x27, 0xf2, 0x1d, 0x9b, 0xbc, 0x94, 0x43, 0x03,
|
||||||
|
0xf8, 0x11, 0xc7, 0xf6, 0x90, 0xef, 0x3e, 0xe7, 0x06, 0xc3, 0xd5, 0x2f, 0xc8, 0x66, 0x1e, 0xd7,
|
||||||
|
0x08, 0xe8, 0xea, 0xde, 0x80, 0x52, 0xee, 0xf7, 0x84, 0xaa, 0x72, 0xac, 0x35, 0x4d, 0x6a, 0x2a,
|
||||||
|
0x96, 0x1a, 0xd2, 0x71, 0x5a, 0x15, 0x49, 0x74, 0x4b, 0x9f, 0xd0, 0x5e, 0x04, 0x18, 0xa4, 0xec,
|
||||||
|
0xc2, 0xe0, 0x41, 0x6e, 0x0f, 0x51, 0xcb, 0xcc, 0x24, 0x91, 0xaf, 0x50, 0xa1, 0xf4, 0x70, 0x39,
|
||||||
|
0x99, 0x7c, 0x3a, 0x85, 0x23, 0xb8, 0xb4, 0x7a, 0xfc, 0x02, 0x36, 0x5b, 0x25, 0x55, 0x97, 0x31,
|
||||||
|
0x2d, 0x5d, 0xfa, 0x98, 0xe3, 0x8a, 0x92, 0xae, 0x05, 0xdf, 0x29, 0x10, 0x67, 0x6c, 0xba, 0xc9,
|
||||||
|
0xd3, 0x00, 0xe6, 0xcf, 0xe1, 0x9e, 0xa8, 0x2c, 0x63, 0x16, 0x01, 0x3f, 0x58, 0xe2, 0x89, 0xa9,
|
||||||
|
0x0d, 0x38, 0x34, 0x1b, 0xab, 0x33, 0xff, 0xb0, 0xbb, 0x48, 0x0c, 0x5f, 0xb9, 0xb1, 0xcd, 0x2e,
|
||||||
|
0xc5, 0xf3, 0xdb, 0x47, 0xe5, 0xa5, 0x9c, 0x77, 0x0a, 0xa6, 0x20, 0x68, 0xfe, 0x7f, 0xc1, 0xad
|
||||||
|
];
|
||||||
|
|
||||||
|
var s = [1, 2, 3, 5];
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rotate a word left by given number of bits.
|
||||||
|
*
|
||||||
|
* Bits that are shifted out on the left are put back in on the right
|
||||||
|
* hand side.
|
||||||
|
*
|
||||||
|
* @param word The word to shift left.
|
||||||
|
* @param bits The number of bits to shift by.
|
||||||
|
* @return The rotated word.
|
||||||
|
*/
|
||||||
|
var rol = function(word, bits) {
|
||||||
|
return ((word << bits) & 0xffff) | ((word & 0xffff) >> (16 - bits));
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rotate a word right by given number of bits.
|
||||||
|
*
|
||||||
|
* Bits that are shifted out on the right are put back in on the left
|
||||||
|
* hand side.
|
||||||
|
*
|
||||||
|
* @param word The word to shift right.
|
||||||
|
* @param bits The number of bits to shift by.
|
||||||
|
* @return The rotated word.
|
||||||
|
*/
|
||||||
|
var ror = function(word, bits) {
|
||||||
|
return ((word & 0xffff) >> bits) | ((word << (16 - bits)) & 0xffff);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* RC2 API */
|
||||||
|
forge.rc2 = forge.rc2 || {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform RC2 key expansion as per RFC #2268, section 2.
|
||||||
|
*
|
||||||
|
* @param key variable-length user key (between 1 and 128 bytes)
|
||||||
|
* @param effKeyBits number of effective key bits (default: 128)
|
||||||
|
* @return the expanded RC2 key (ByteBuffer of 128 bytes)
|
||||||
|
*/
|
||||||
|
forge.rc2.expandKey = function(key, effKeyBits) {
|
||||||
|
if(typeof key === 'string') {
|
||||||
|
key = forge.util.createBuffer(key);
|
||||||
|
}
|
||||||
|
effKeyBits = effKeyBits || 128;
|
||||||
|
|
||||||
|
/* introduce variables that match the names used in RFC #2268 */
|
||||||
|
var L = key;
|
||||||
|
var T = key.length();
|
||||||
|
var T1 = effKeyBits;
|
||||||
|
var T8 = Math.ceil(T1 / 8);
|
||||||
|
var TM = 0xff >> (T1 & 0x07);
|
||||||
|
var i;
|
||||||
|
|
||||||
|
for(i = T; i < 128; i ++) {
|
||||||
|
L.putByte(piTable[(L.at(i - 1) + L.at(i - T)) & 0xff]);
|
||||||
|
}
|
||||||
|
|
||||||
|
L.setAt(128 - T8, piTable[L.at(128 - T8) & TM]);
|
||||||
|
|
||||||
|
for(i = 127 - T8; i >= 0; i --) {
|
||||||
|
L.setAt(i, piTable[L.at(i + 1) ^ L.at(i + T8)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return L;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a RC2 cipher object.
|
||||||
|
*
|
||||||
|
* @param key the symmetric key to use (as base for key generation).
|
||||||
|
* @param bits the number of effective key bits.
|
||||||
|
* @param encrypt false for decryption, true for encryption.
|
||||||
|
*
|
||||||
|
* @return the cipher.
|
||||||
|
*/
|
||||||
|
var createCipher = function(key, bits, encrypt) {
|
||||||
|
var _finish = false, _input = null, _output = null, _iv = null;
|
||||||
|
var mixRound, mashRound;
|
||||||
|
var i, j, K = [];
|
||||||
|
|
||||||
|
/* Expand key and fill into K[] Array */
|
||||||
|
key = forge.rc2.expandKey(key, bits);
|
||||||
|
for(i = 0; i < 64; i ++) {
|
||||||
|
K.push(key.getInt16Le());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(encrypt) {
|
||||||
|
/**
|
||||||
|
* Perform one mixing round "in place".
|
||||||
|
*
|
||||||
|
* @param R Array of four words to perform mixing on.
|
||||||
|
*/
|
||||||
|
mixRound = function(R) {
|
||||||
|
for(i = 0; i < 4; i++) {
|
||||||
|
R[i] += K[j] + (R[(i + 3) % 4] & R[(i + 2) % 4]) +
|
||||||
|
((~R[(i + 3) % 4]) & R[(i + 1) % 4]);
|
||||||
|
R[i] = rol(R[i], s[i]);
|
||||||
|
j ++;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform one mashing round "in place".
|
||||||
|
*
|
||||||
|
* @param R Array of four words to perform mashing on.
|
||||||
|
*/
|
||||||
|
mashRound = function(R) {
|
||||||
|
for(i = 0; i < 4; i ++) {
|
||||||
|
R[i] += K[R[(i + 3) % 4] & 63];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
/**
|
||||||
|
* Perform one r-mixing round "in place".
|
||||||
|
*
|
||||||
|
* @param R Array of four words to perform mixing on.
|
||||||
|
*/
|
||||||
|
mixRound = function(R) {
|
||||||
|
for(i = 3; i >= 0; i--) {
|
||||||
|
R[i] = ror(R[i], s[i]);
|
||||||
|
R[i] -= K[j] + (R[(i + 3) % 4] & R[(i + 2) % 4]) +
|
||||||
|
((~R[(i + 3) % 4]) & R[(i + 1) % 4]);
|
||||||
|
j --;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform one r-mashing round "in place".
|
||||||
|
*
|
||||||
|
* @param R Array of four words to perform mashing on.
|
||||||
|
*/
|
||||||
|
mashRound = function(R) {
|
||||||
|
for(i = 3; i >= 0; i--) {
|
||||||
|
R[i] -= K[R[(i + 3) % 4] & 63];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run the specified cipher execution plan.
|
||||||
|
*
|
||||||
|
* This function takes four words from the input buffer, applies the IV on
|
||||||
|
* it (if requested) and runs the provided execution plan.
|
||||||
|
*
|
||||||
|
* The plan must be put together in form of a array of arrays. Where the
|
||||||
|
* outer one is simply a list of steps to perform and the inner one needs
|
||||||
|
* to have two elements: the first one telling how many rounds to perform,
|
||||||
|
* the second one telling what to do (i.e. the function to call).
|
||||||
|
*
|
||||||
|
* @param {Array} plan The plan to execute.
|
||||||
|
*/
|
||||||
|
var runPlan = function(plan) {
|
||||||
|
var R = [];
|
||||||
|
|
||||||
|
/* Get data from input buffer and fill the four words into R */
|
||||||
|
for(i = 0; i < 4; i ++) {
|
||||||
|
var val = _input.getInt16Le();
|
||||||
|
|
||||||
|
if(_iv !== null) {
|
||||||
|
if(encrypt) {
|
||||||
|
/* We're encrypting, apply the IV first. */
|
||||||
|
val ^= _iv.getInt16Le();
|
||||||
|
} else {
|
||||||
|
/* We're decryption, keep cipher text for next block. */
|
||||||
|
_iv.putInt16Le(val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
R.push(val & 0xffff);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reset global "j" variable as per spec. */
|
||||||
|
j = encrypt ? 0 : 63;
|
||||||
|
|
||||||
|
/* Run execution plan. */
|
||||||
|
for(var ptr = 0; ptr < plan.length; ptr ++) {
|
||||||
|
for(var ctr = 0; ctr < plan[ptr][0]; ctr ++) {
|
||||||
|
plan[ptr][1](R);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write back result to output buffer. */
|
||||||
|
for(i = 0; i < 4; i ++) {
|
||||||
|
if(_iv !== null) {
|
||||||
|
if(encrypt) {
|
||||||
|
/* We're encrypting in CBC-mode, feed back encrypted bytes into
|
||||||
|
IV buffer to carry it forward to next block. */
|
||||||
|
_iv.putInt16Le(R[i]);
|
||||||
|
} else {
|
||||||
|
R[i] ^= _iv.getInt16Le();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_output.putInt16Le(R[i]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* Create cipher object */
|
||||||
|
var cipher = null;
|
||||||
|
cipher = {
|
||||||
|
/**
|
||||||
|
* Starts or restarts the encryption or decryption process, whichever
|
||||||
|
* was previously configured.
|
||||||
|
*
|
||||||
|
* To use the cipher in CBC mode, iv may be given either as a string
|
||||||
|
* of bytes, or as a byte buffer. For ECB mode, give null as iv.
|
||||||
|
*
|
||||||
|
* @param iv the initialization vector to use, null for ECB mode.
|
||||||
|
* @param output the output the buffer to write to, null to create one.
|
||||||
|
*/
|
||||||
|
start: function(iv, output) {
|
||||||
|
if(iv) {
|
||||||
|
/* CBC mode */
|
||||||
|
if(typeof iv === 'string') {
|
||||||
|
iv = forge.util.createBuffer(iv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_finish = false;
|
||||||
|
_input = forge.util.createBuffer();
|
||||||
|
_output = output || new forge.util.createBuffer();
|
||||||
|
_iv = iv;
|
||||||
|
|
||||||
|
cipher.output = _output;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the next block.
|
||||||
|
*
|
||||||
|
* @param input the buffer to read from.
|
||||||
|
*/
|
||||||
|
update: function(input) {
|
||||||
|
if(!_finish) {
|
||||||
|
// not finishing, so fill the input buffer with more input
|
||||||
|
_input.putBuffer(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
while(_input.length() >= 8) {
|
||||||
|
runPlan([
|
||||||
|
[ 5, mixRound ],
|
||||||
|
[ 1, mashRound ],
|
||||||
|
[ 6, mixRound ],
|
||||||
|
[ 1, mashRound ],
|
||||||
|
[ 5, mixRound ]
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finishes encrypting or decrypting.
|
||||||
|
*
|
||||||
|
* @param pad a padding function to use, null for PKCS#7 padding,
|
||||||
|
* signature(blockSize, buffer, decrypt).
|
||||||
|
*
|
||||||
|
* @return true if successful, false on error.
|
||||||
|
*/
|
||||||
|
finish: function(pad) {
|
||||||
|
var rval = true;
|
||||||
|
|
||||||
|
if(encrypt) {
|
||||||
|
if(pad) {
|
||||||
|
rval = pad(8, _input, !encrypt);
|
||||||
|
} else {
|
||||||
|
// add PKCS#7 padding to block (each pad byte is the
|
||||||
|
// value of the number of pad bytes)
|
||||||
|
var padding = (_input.length() === 8) ? 8 : (8 - _input.length());
|
||||||
|
_input.fillWithByte(padding, padding);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(rval) {
|
||||||
|
// do final update
|
||||||
|
_finish = true;
|
||||||
|
cipher.update();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!encrypt) {
|
||||||
|
// check for error: input data not a multiple of block size
|
||||||
|
rval = (_input.length() === 0);
|
||||||
|
if(rval) {
|
||||||
|
if(pad) {
|
||||||
|
rval = pad(8, _output, !encrypt);
|
||||||
|
} else {
|
||||||
|
// ensure padding byte count is valid
|
||||||
|
var len = _output.length();
|
||||||
|
var count = _output.at(len - 1);
|
||||||
|
|
||||||
|
if(count > len) {
|
||||||
|
rval = false;
|
||||||
|
} else {
|
||||||
|
// trim off padding bytes
|
||||||
|
_output.truncate(count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rval;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return cipher;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an RC2 cipher object to encrypt data in ECB or CBC mode using the
|
||||||
|
* given symmetric key. The output will be stored in the 'output' member
|
||||||
|
* of the returned cipher.
|
||||||
|
*
|
||||||
|
* The key and iv may be given as a string of bytes or a byte buffer.
|
||||||
|
* The cipher is initialized to use 128 effective key bits.
|
||||||
|
*
|
||||||
|
* @param key the symmetric key to use.
|
||||||
|
* @param iv the initialization vector to use.
|
||||||
|
* @param output the buffer to write to, null to create one.
|
||||||
|
*
|
||||||
|
* @return the cipher.
|
||||||
|
*/
|
||||||
|
forge.rc2.startEncrypting = function(key, iv, output) {
|
||||||
|
var cipher = forge.rc2.createEncryptionCipher(key, 128);
|
||||||
|
cipher.start(iv, output);
|
||||||
|
return cipher;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an RC2 cipher object to encrypt data in ECB or CBC mode using the
|
||||||
|
* given symmetric key.
|
||||||
|
*
|
||||||
|
* The key may be given as a string of bytes or a byte buffer.
|
||||||
|
*
|
||||||
|
* To start encrypting call start() on the cipher with an iv and optional
|
||||||
|
* output buffer.
|
||||||
|
*
|
||||||
|
* @param key the symmetric key to use.
|
||||||
|
*
|
||||||
|
* @return the cipher.
|
||||||
|
*/
|
||||||
|
forge.rc2.createEncryptionCipher = function(key, bits) {
|
||||||
|
return createCipher(key, bits, true);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an RC2 cipher object to decrypt data in ECB or CBC mode using the
|
||||||
|
* given symmetric key. The output will be stored in the 'output' member
|
||||||
|
* of the returned cipher.
|
||||||
|
*
|
||||||
|
* The key and iv may be given as a string of bytes or a byte buffer.
|
||||||
|
* The cipher is initialized to use 128 effective key bits.
|
||||||
|
*
|
||||||
|
* @param key the symmetric key to use.
|
||||||
|
* @param iv the initialization vector to use.
|
||||||
|
* @param output the buffer to write to, null to create one.
|
||||||
|
*
|
||||||
|
* @return the cipher.
|
||||||
|
*/
|
||||||
|
forge.rc2.startDecrypting = function(key, iv, output) {
|
||||||
|
var cipher = forge.rc2.createDecryptionCipher(key, 128);
|
||||||
|
cipher.start(iv, output);
|
||||||
|
return cipher;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an RC2 cipher object to decrypt data in ECB or CBC mode using the
|
||||||
|
* given symmetric key.
|
||||||
|
*
|
||||||
|
* The key may be given as a string of bytes or a byte buffer.
|
||||||
|
*
|
||||||
|
* To start decrypting call start() on the cipher with an iv and optional
|
||||||
|
* output buffer.
|
||||||
|
*
|
||||||
|
* @param key the symmetric key to use.
|
||||||
|
*
|
||||||
|
* @return the cipher.
|
||||||
|
*/
|
||||||
|
forge.rc2.createDecryptionCipher = function(key, bits) {
|
||||||
|
return createCipher(key, bits, false);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // end module implementation
|
||||||
|
|
||||||
|
/* ########## Begin module wrapper ########## */
|
||||||
|
var name = 'rc2';
|
||||||
|
if(typeof define !== 'function') {
|
||||||
|
// NodeJS -> AMD
|
||||||
|
if(typeof module === 'object' && module.exports) {
|
||||||
|
var nodeJS = true;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
factory(require, module);
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
// <script>
|
||||||
|
if(typeof forge === 'undefined') {
|
||||||
|
forge = {};
|
||||||
|
}
|
||||||
|
return initModule(forge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// AMD
|
||||||
|
var deps;
|
||||||
|
var defineFunc = function(require, module) {
|
||||||
|
module.exports = function(forge) {
|
||||||
|
var mods = deps.map(function(dep) {
|
||||||
|
return require(dep);
|
||||||
|
}).concat(initModule);
|
||||||
|
// handle circular dependencies
|
||||||
|
forge = forge || {};
|
||||||
|
forge.defined = forge.defined || {};
|
||||||
|
if(forge.defined[name]) {
|
||||||
|
return forge[name];
|
||||||
|
}
|
||||||
|
forge.defined[name] = true;
|
||||||
|
for(var i = 0; i < mods.length; ++i) {
|
||||||
|
mods[i](forge);
|
||||||
|
}
|
||||||
|
return forge[name];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
var tmpDefine = define;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
|
||||||
|
if(nodeJS) {
|
||||||
|
delete define;
|
||||||
|
return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
}
|
||||||
|
define = tmpDefine;
|
||||||
|
return define.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
};
|
||||||
|
define(['require', 'module', './util'], function() {
|
||||||
|
defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
});
|
||||||
|
})();
|
||||||
1714
forge.js/rsa.js
Normal file
369
forge.js/sha1.js
Normal file
@@ -0,0 +1,369 @@
|
|||||||
|
/**
|
||||||
|
* Secure Hash Algorithm with 160-bit digest (SHA-1) implementation.
|
||||||
|
*
|
||||||
|
* @author Dave Longley
|
||||||
|
*
|
||||||
|
* Copyright (c) 2010-2015 Digital Bazaar, Inc.
|
||||||
|
*/
|
||||||
|
(function() {
|
||||||
|
/* ########## Begin module implementation ########## */
|
||||||
|
function initModule(forge) {
|
||||||
|
|
||||||
|
var sha1 = forge.sha1 = forge.sha1 || {};
|
||||||
|
forge.md = forge.md || {};
|
||||||
|
forge.md.algorithms = forge.md.algorithms || {};
|
||||||
|
forge.md.sha1 = forge.md.algorithms.sha1 = sha1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a SHA-1 message digest object.
|
||||||
|
*
|
||||||
|
* @return a message digest object.
|
||||||
|
*/
|
||||||
|
sha1.create = function() {
|
||||||
|
// do initialization as necessary
|
||||||
|
if(!_initialized) {
|
||||||
|
_init();
|
||||||
|
}
|
||||||
|
|
||||||
|
// SHA-1 state contains five 32-bit integers
|
||||||
|
var _state = null;
|
||||||
|
|
||||||
|
// input buffer
|
||||||
|
var _input = forge.util.createBuffer();
|
||||||
|
|
||||||
|
// used for word storage
|
||||||
|
var _w = new Array(80);
|
||||||
|
|
||||||
|
// message digest object
|
||||||
|
var md = {
|
||||||
|
algorithm: 'sha1',
|
||||||
|
blockLength: 64,
|
||||||
|
digestLength: 20,
|
||||||
|
// 56-bit length of message so far (does not including padding)
|
||||||
|
messageLength: 0,
|
||||||
|
// true message length
|
||||||
|
fullMessageLength: null,
|
||||||
|
// size of message length in bytes
|
||||||
|
messageLengthSize: 8
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts the digest.
|
||||||
|
*
|
||||||
|
* @return this digest object.
|
||||||
|
*/
|
||||||
|
md.start = function() {
|
||||||
|
// up to 56-bit message length for convenience
|
||||||
|
md.messageLength = 0;
|
||||||
|
|
||||||
|
// full message length (set md.messageLength64 for backwards-compatibility)
|
||||||
|
md.fullMessageLength = md.messageLength64 = [];
|
||||||
|
var int32s = md.messageLengthSize / 4;
|
||||||
|
for(var i = 0; i < int32s; ++i) {
|
||||||
|
md.fullMessageLength.push(0);
|
||||||
|
}
|
||||||
|
_input = forge.util.createBuffer();
|
||||||
|
_state = {
|
||||||
|
h0: 0x67452301,
|
||||||
|
h1: 0xEFCDAB89,
|
||||||
|
h2: 0x98BADCFE,
|
||||||
|
h3: 0x10325476,
|
||||||
|
h4: 0xC3D2E1F0
|
||||||
|
};
|
||||||
|
return md;
|
||||||
|
};
|
||||||
|
// start digest automatically for first time
|
||||||
|
md.start();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the digest with the given message input. The given input can
|
||||||
|
* treated as raw input (no encoding will be applied) or an encoding of
|
||||||
|
* 'utf8' maybe given to encode the input using UTF-8.
|
||||||
|
*
|
||||||
|
* @param msg the message input to update with.
|
||||||
|
* @param encoding the encoding to use (default: 'raw', other: 'utf8').
|
||||||
|
*
|
||||||
|
* @return this digest object.
|
||||||
|
*/
|
||||||
|
md.update = function(msg, encoding) {
|
||||||
|
if(encoding === 'utf8') {
|
||||||
|
msg = forge.util.encodeUtf8(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
// update message length
|
||||||
|
var len = msg.length;
|
||||||
|
md.messageLength += len;
|
||||||
|
len = [(len / 0x100000000) >>> 0, len >>> 0];
|
||||||
|
for(var i = md.fullMessageLength.length - 1; i >= 0; --i) {
|
||||||
|
md.fullMessageLength[i] += len[1];
|
||||||
|
len[1] = len[0] + ((md.fullMessageLength[i] / 0x100000000) >>> 0);
|
||||||
|
md.fullMessageLength[i] = md.fullMessageLength[i] >>> 0;
|
||||||
|
len[0] = ((len[1] / 0x100000000) >>> 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// add bytes to input buffer
|
||||||
|
_input.putBytes(msg);
|
||||||
|
|
||||||
|
// process bytes
|
||||||
|
_update(_state, _w, _input);
|
||||||
|
|
||||||
|
// compact input buffer every 2K or if empty
|
||||||
|
if(_input.read > 2048 || _input.length() === 0) {
|
||||||
|
_input.compact();
|
||||||
|
}
|
||||||
|
|
||||||
|
return md;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Produces the digest.
|
||||||
|
*
|
||||||
|
* @return a byte buffer containing the digest value.
|
||||||
|
*/
|
||||||
|
md.digest = function() {
|
||||||
|
/* Note: Here we copy the remaining bytes in the input buffer and
|
||||||
|
add the appropriate SHA-1 padding. Then we do the final update
|
||||||
|
on a copy of the state so that if the user wants to get
|
||||||
|
intermediate digests they can do so. */
|
||||||
|
|
||||||
|
/* Determine the number of bytes that must be added to the message
|
||||||
|
to ensure its length is congruent to 448 mod 512. In other words,
|
||||||
|
the data to be digested must be a multiple of 512 bits (or 128 bytes).
|
||||||
|
This data includes the message, some padding, and the length of the
|
||||||
|
message. Since the length of the message will be encoded as 8 bytes (64
|
||||||
|
bits), that means that the last segment of the data must have 56 bytes
|
||||||
|
(448 bits) of message and padding. Therefore, the length of the message
|
||||||
|
plus the padding must be congruent to 448 mod 512 because
|
||||||
|
512 - 128 = 448.
|
||||||
|
|
||||||
|
In order to fill up the message length it must be filled with
|
||||||
|
padding that begins with 1 bit followed by all 0 bits. Padding
|
||||||
|
must *always* be present, so if the message length is already
|
||||||
|
congruent to 448 mod 512, then 512 padding bits must be added. */
|
||||||
|
|
||||||
|
var finalBlock = forge.util.createBuffer();
|
||||||
|
finalBlock.putBytes(_input.bytes());
|
||||||
|
|
||||||
|
// compute remaining size to be digested (include message length size)
|
||||||
|
var remaining = (
|
||||||
|
md.fullMessageLength[md.fullMessageLength.length - 1] +
|
||||||
|
md.messageLengthSize);
|
||||||
|
|
||||||
|
// add padding for overflow blockSize - overflow
|
||||||
|
// _padding starts with 1 byte with first bit is set (byte value 128), then
|
||||||
|
// there may be up to (blockSize - 1) other pad bytes
|
||||||
|
var overflow = remaining & (md.blockLength - 1);
|
||||||
|
finalBlock.putBytes(_padding.substr(0, md.blockLength - overflow));
|
||||||
|
|
||||||
|
// serialize message length in bits in big-endian order; since length
|
||||||
|
// is stored in bytes we multiply by 8 and add carry from next int
|
||||||
|
var messageLength = forge.util.createBuffer();
|
||||||
|
var next, carry;
|
||||||
|
var bits = md.fullMessageLength[0] * 8;
|
||||||
|
for(var i = 0; i < md.fullMessageLength.length; ++i) {
|
||||||
|
next = md.fullMessageLength[i + 1] * 8;
|
||||||
|
carry = (next / 0x100000000) >>> 0;
|
||||||
|
bits += carry;
|
||||||
|
finalBlock.putInt32(bits >>> 0);
|
||||||
|
bits = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
var s2 = {
|
||||||
|
h0: _state.h0,
|
||||||
|
h1: _state.h1,
|
||||||
|
h2: _state.h2,
|
||||||
|
h3: _state.h3,
|
||||||
|
h4: _state.h4
|
||||||
|
};
|
||||||
|
_update(s2, _w, finalBlock);
|
||||||
|
var rval = forge.util.createBuffer();
|
||||||
|
rval.putInt32(s2.h0);
|
||||||
|
rval.putInt32(s2.h1);
|
||||||
|
rval.putInt32(s2.h2);
|
||||||
|
rval.putInt32(s2.h3);
|
||||||
|
rval.putInt32(s2.h4);
|
||||||
|
return rval;
|
||||||
|
};
|
||||||
|
|
||||||
|
return md;
|
||||||
|
};
|
||||||
|
|
||||||
|
// sha-1 padding bytes not initialized yet
|
||||||
|
var _padding = null;
|
||||||
|
var _initialized = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the constant tables.
|
||||||
|
*/
|
||||||
|
function _init() {
|
||||||
|
// create padding
|
||||||
|
_padding = String.fromCharCode(128);
|
||||||
|
_padding += forge.util.fillString(String.fromCharCode(0x00), 64);
|
||||||
|
|
||||||
|
// now initialized
|
||||||
|
_initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates a SHA-1 state with the given byte buffer.
|
||||||
|
*
|
||||||
|
* @param s the SHA-1 state to update.
|
||||||
|
* @param w the array to use to store words.
|
||||||
|
* @param bytes the byte buffer to update with.
|
||||||
|
*/
|
||||||
|
function _update(s, w, bytes) {
|
||||||
|
// consume 512 bit (64 byte) chunks
|
||||||
|
var t, a, b, c, d, e, f, i;
|
||||||
|
var len = bytes.length();
|
||||||
|
while(len >= 64) {
|
||||||
|
// the w array will be populated with sixteen 32-bit big-endian words
|
||||||
|
// and then extended into 80 32-bit words according to SHA-1 algorithm
|
||||||
|
// and for 32-79 using Max Locktyukhin's optimization
|
||||||
|
|
||||||
|
// initialize hash value for this chunk
|
||||||
|
a = s.h0;
|
||||||
|
b = s.h1;
|
||||||
|
c = s.h2;
|
||||||
|
d = s.h3;
|
||||||
|
e = s.h4;
|
||||||
|
|
||||||
|
// round 1
|
||||||
|
for(i = 0; i < 16; ++i) {
|
||||||
|
t = bytes.getInt32();
|
||||||
|
w[i] = t;
|
||||||
|
f = d ^ (b & (c ^ d));
|
||||||
|
t = ((a << 5) | (a >>> 27)) + f + e + 0x5A827999 + t;
|
||||||
|
e = d;
|
||||||
|
d = c;
|
||||||
|
c = (b << 30) | (b >>> 2);
|
||||||
|
b = a;
|
||||||
|
a = t;
|
||||||
|
}
|
||||||
|
for(; i < 20; ++i) {
|
||||||
|
t = (w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]);
|
||||||
|
t = (t << 1) | (t >>> 31);
|
||||||
|
w[i] = t;
|
||||||
|
f = d ^ (b & (c ^ d));
|
||||||
|
t = ((a << 5) | (a >>> 27)) + f + e + 0x5A827999 + t;
|
||||||
|
e = d;
|
||||||
|
d = c;
|
||||||
|
c = (b << 30) | (b >>> 2);
|
||||||
|
b = a;
|
||||||
|
a = t;
|
||||||
|
}
|
||||||
|
// round 2
|
||||||
|
for(; i < 32; ++i) {
|
||||||
|
t = (w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]);
|
||||||
|
t = (t << 1) | (t >>> 31);
|
||||||
|
w[i] = t;
|
||||||
|
f = b ^ c ^ d;
|
||||||
|
t = ((a << 5) | (a >>> 27)) + f + e + 0x6ED9EBA1 + t;
|
||||||
|
e = d;
|
||||||
|
d = c;
|
||||||
|
c = (b << 30) | (b >>> 2);
|
||||||
|
b = a;
|
||||||
|
a = t;
|
||||||
|
}
|
||||||
|
for(; i < 40; ++i) {
|
||||||
|
t = (w[i - 6] ^ w[i - 16] ^ w[i - 28] ^ w[i - 32]);
|
||||||
|
t = (t << 2) | (t >>> 30);
|
||||||
|
w[i] = t;
|
||||||
|
f = b ^ c ^ d;
|
||||||
|
t = ((a << 5) | (a >>> 27)) + f + e + 0x6ED9EBA1 + t;
|
||||||
|
e = d;
|
||||||
|
d = c;
|
||||||
|
c = (b << 30) | (b >>> 2);
|
||||||
|
b = a;
|
||||||
|
a = t;
|
||||||
|
}
|
||||||
|
// round 3
|
||||||
|
for(; i < 60; ++i) {
|
||||||
|
t = (w[i - 6] ^ w[i - 16] ^ w[i - 28] ^ w[i - 32]);
|
||||||
|
t = (t << 2) | (t >>> 30);
|
||||||
|
w[i] = t;
|
||||||
|
f = (b & c) | (d & (b ^ c));
|
||||||
|
t = ((a << 5) | (a >>> 27)) + f + e + 0x8F1BBCDC + t;
|
||||||
|
e = d;
|
||||||
|
d = c;
|
||||||
|
c = (b << 30) | (b >>> 2);
|
||||||
|
b = a;
|
||||||
|
a = t;
|
||||||
|
}
|
||||||
|
// round 4
|
||||||
|
for(; i < 80; ++i) {
|
||||||
|
t = (w[i - 6] ^ w[i - 16] ^ w[i - 28] ^ w[i - 32]);
|
||||||
|
t = (t << 2) | (t >>> 30);
|
||||||
|
w[i] = t;
|
||||||
|
f = b ^ c ^ d;
|
||||||
|
t = ((a << 5) | (a >>> 27)) + f + e + 0xCA62C1D6 + t;
|
||||||
|
e = d;
|
||||||
|
d = c;
|
||||||
|
c = (b << 30) | (b >>> 2);
|
||||||
|
b = a;
|
||||||
|
a = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
// update hash state
|
||||||
|
s.h0 = (s.h0 + a) | 0;
|
||||||
|
s.h1 = (s.h1 + b) | 0;
|
||||||
|
s.h2 = (s.h2 + c) | 0;
|
||||||
|
s.h3 = (s.h3 + d) | 0;
|
||||||
|
s.h4 = (s.h4 + e) | 0;
|
||||||
|
|
||||||
|
len -= 64;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end module implementation
|
||||||
|
|
||||||
|
/* ########## Begin module wrapper ########## */
|
||||||
|
var name = 'sha1';
|
||||||
|
if(typeof define !== 'function') {
|
||||||
|
// NodeJS -> AMD
|
||||||
|
if(typeof module === 'object' && module.exports) {
|
||||||
|
var nodeJS = true;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
factory(require, module);
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
// <script>
|
||||||
|
if(typeof forge === 'undefined') {
|
||||||
|
forge = {};
|
||||||
|
}
|
||||||
|
return initModule(forge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// AMD
|
||||||
|
var deps;
|
||||||
|
var defineFunc = function(require, module) {
|
||||||
|
module.exports = function(forge) {
|
||||||
|
var mods = deps.map(function(dep) {
|
||||||
|
return require(dep);
|
||||||
|
}).concat(initModule);
|
||||||
|
// handle circular dependencies
|
||||||
|
forge = forge || {};
|
||||||
|
forge.defined = forge.defined || {};
|
||||||
|
if(forge.defined[name]) {
|
||||||
|
return forge[name];
|
||||||
|
}
|
||||||
|
forge.defined[name] = true;
|
||||||
|
for(var i = 0; i < mods.length; ++i) {
|
||||||
|
mods[i](forge);
|
||||||
|
}
|
||||||
|
return forge[name];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
var tmpDefine = define;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
|
||||||
|
if(nodeJS) {
|
||||||
|
delete define;
|
||||||
|
return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
}
|
||||||
|
define = tmpDefine;
|
||||||
|
return define.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
};
|
||||||
|
define(['require', 'module', './util'], function() {
|
||||||
|
defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
});
|
||||||
|
})();
|
||||||
379
forge.js/sha256.js
Normal file
@@ -0,0 +1,379 @@
|
|||||||
|
/**
|
||||||
|
* Secure Hash Algorithm with 256-bit digest (SHA-256) implementation.
|
||||||
|
*
|
||||||
|
* See FIPS 180-2 for details.
|
||||||
|
*
|
||||||
|
* @author Dave Longley
|
||||||
|
*
|
||||||
|
* Copyright (c) 2010-2015 Digital Bazaar, Inc.
|
||||||
|
*/
|
||||||
|
(function() {
|
||||||
|
/* ########## Begin module implementation ########## */
|
||||||
|
function initModule(forge) {
|
||||||
|
|
||||||
|
var sha256 = forge.sha256 = forge.sha256 || {};
|
||||||
|
forge.md = forge.md || {};
|
||||||
|
forge.md.algorithms = forge.md.algorithms || {};
|
||||||
|
forge.md.sha256 = forge.md.algorithms.sha256 = sha256;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a SHA-256 message digest object.
|
||||||
|
*
|
||||||
|
* @return a message digest object.
|
||||||
|
*/
|
||||||
|
sha256.create = function() {
|
||||||
|
// do initialization as necessary
|
||||||
|
if(!_initialized) {
|
||||||
|
_init();
|
||||||
|
}
|
||||||
|
|
||||||
|
// SHA-256 state contains eight 32-bit integers
|
||||||
|
var _state = null;
|
||||||
|
|
||||||
|
// input buffer
|
||||||
|
var _input = forge.util.createBuffer();
|
||||||
|
|
||||||
|
// used for word storage
|
||||||
|
var _w = new Array(64);
|
||||||
|
|
||||||
|
// message digest object
|
||||||
|
var md = {
|
||||||
|
algorithm: 'sha256',
|
||||||
|
blockLength: 64,
|
||||||
|
digestLength: 32,
|
||||||
|
// 56-bit length of message so far (does not including padding)
|
||||||
|
messageLength: 0,
|
||||||
|
// true message length
|
||||||
|
fullMessageLength: null,
|
||||||
|
// size of message length in bytes
|
||||||
|
messageLengthSize: 8
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts the digest.
|
||||||
|
*
|
||||||
|
* @return this digest object.
|
||||||
|
*/
|
||||||
|
md.start = function() {
|
||||||
|
// up to 56-bit message length for convenience
|
||||||
|
md.messageLength = 0;
|
||||||
|
|
||||||
|
// full message length (set md.messageLength64 for backwards-compatibility)
|
||||||
|
md.fullMessageLength = md.messageLength64 = [];
|
||||||
|
var int32s = md.messageLengthSize / 4;
|
||||||
|
for(var i = 0; i < int32s; ++i) {
|
||||||
|
md.fullMessageLength.push(0);
|
||||||
|
}
|
||||||
|
_input = forge.util.createBuffer();
|
||||||
|
_state = {
|
||||||
|
h0: 0x6A09E667,
|
||||||
|
h1: 0xBB67AE85,
|
||||||
|
h2: 0x3C6EF372,
|
||||||
|
h3: 0xA54FF53A,
|
||||||
|
h4: 0x510E527F,
|
||||||
|
h5: 0x9B05688C,
|
||||||
|
h6: 0x1F83D9AB,
|
||||||
|
h7: 0x5BE0CD19
|
||||||
|
};
|
||||||
|
return md;
|
||||||
|
};
|
||||||
|
// start digest automatically for first time
|
||||||
|
md.start();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the digest with the given message input. The given input can
|
||||||
|
* treated as raw input (no encoding will be applied) or an encoding of
|
||||||
|
* 'utf8' maybe given to encode the input using UTF-8.
|
||||||
|
*
|
||||||
|
* @param msg the message input to update with.
|
||||||
|
* @param encoding the encoding to use (default: 'raw', other: 'utf8').
|
||||||
|
*
|
||||||
|
* @return this digest object.
|
||||||
|
*/
|
||||||
|
md.update = function(msg, encoding) {
|
||||||
|
if(encoding === 'utf8') {
|
||||||
|
msg = forge.util.encodeUtf8(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
// update message length
|
||||||
|
var len = msg.length;
|
||||||
|
md.messageLength += len;
|
||||||
|
len = [(len / 0x100000000) >>> 0, len >>> 0];
|
||||||
|
for(var i = md.fullMessageLength.length - 1; i >= 0; --i) {
|
||||||
|
md.fullMessageLength[i] += len[1];
|
||||||
|
len[1] = len[0] + ((md.fullMessageLength[i] / 0x100000000) >>> 0);
|
||||||
|
md.fullMessageLength[i] = md.fullMessageLength[i] >>> 0;
|
||||||
|
len[0] = ((len[1] / 0x100000000) >>> 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// add bytes to input buffer
|
||||||
|
_input.putBytes(msg);
|
||||||
|
|
||||||
|
// process bytes
|
||||||
|
_update(_state, _w, _input);
|
||||||
|
|
||||||
|
// compact input buffer every 2K or if empty
|
||||||
|
if(_input.read > 2048 || _input.length() === 0) {
|
||||||
|
_input.compact();
|
||||||
|
}
|
||||||
|
|
||||||
|
return md;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Produces the digest.
|
||||||
|
*
|
||||||
|
* @return a byte buffer containing the digest value.
|
||||||
|
*/
|
||||||
|
md.digest = function() {
|
||||||
|
/* Note: Here we copy the remaining bytes in the input buffer and
|
||||||
|
add the appropriate SHA-256 padding. Then we do the final update
|
||||||
|
on a copy of the state so that if the user wants to get
|
||||||
|
intermediate digests they can do so. */
|
||||||
|
|
||||||
|
/* Determine the number of bytes that must be added to the message
|
||||||
|
to ensure its length is congruent to 448 mod 512. In other words,
|
||||||
|
the data to be digested must be a multiple of 512 bits (or 128 bytes).
|
||||||
|
This data includes the message, some padding, and the length of the
|
||||||
|
message. Since the length of the message will be encoded as 8 bytes (64
|
||||||
|
bits), that means that the last segment of the data must have 56 bytes
|
||||||
|
(448 bits) of message and padding. Therefore, the length of the message
|
||||||
|
plus the padding must be congruent to 448 mod 512 because
|
||||||
|
512 - 128 = 448.
|
||||||
|
|
||||||
|
In order to fill up the message length it must be filled with
|
||||||
|
padding that begins with 1 bit followed by all 0 bits. Padding
|
||||||
|
must *always* be present, so if the message length is already
|
||||||
|
congruent to 448 mod 512, then 512 padding bits must be added. */
|
||||||
|
|
||||||
|
var finalBlock = forge.util.createBuffer();
|
||||||
|
finalBlock.putBytes(_input.bytes());
|
||||||
|
|
||||||
|
// compute remaining size to be digested (include message length size)
|
||||||
|
var remaining = (
|
||||||
|
md.fullMessageLength[md.fullMessageLength.length - 1] +
|
||||||
|
md.messageLengthSize);
|
||||||
|
|
||||||
|
// add padding for overflow blockSize - overflow
|
||||||
|
// _padding starts with 1 byte with first bit is set (byte value 128), then
|
||||||
|
// there may be up to (blockSize - 1) other pad bytes
|
||||||
|
var overflow = remaining & (md.blockLength - 1);
|
||||||
|
finalBlock.putBytes(_padding.substr(0, md.blockLength - overflow));
|
||||||
|
|
||||||
|
// serialize message length in bits in big-endian order; since length
|
||||||
|
// is stored in bytes we multiply by 8 and add carry from next int
|
||||||
|
var messageLength = forge.util.createBuffer();
|
||||||
|
var next, carry;
|
||||||
|
var bits = md.fullMessageLength[0] * 8;
|
||||||
|
for(var i = 0; i < md.fullMessageLength.length; ++i) {
|
||||||
|
next = md.fullMessageLength[i + 1] * 8;
|
||||||
|
carry = (next / 0x100000000) >>> 0;
|
||||||
|
bits += carry;
|
||||||
|
finalBlock.putInt32(bits >>> 0);
|
||||||
|
bits = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
var s2 = {
|
||||||
|
h0: _state.h0,
|
||||||
|
h1: _state.h1,
|
||||||
|
h2: _state.h2,
|
||||||
|
h3: _state.h3,
|
||||||
|
h4: _state.h4,
|
||||||
|
h5: _state.h5,
|
||||||
|
h6: _state.h6,
|
||||||
|
h7: _state.h7
|
||||||
|
};
|
||||||
|
_update(s2, _w, finalBlock);
|
||||||
|
var rval = forge.util.createBuffer();
|
||||||
|
rval.putInt32(s2.h0);
|
||||||
|
rval.putInt32(s2.h1);
|
||||||
|
rval.putInt32(s2.h2);
|
||||||
|
rval.putInt32(s2.h3);
|
||||||
|
rval.putInt32(s2.h4);
|
||||||
|
rval.putInt32(s2.h5);
|
||||||
|
rval.putInt32(s2.h6);
|
||||||
|
rval.putInt32(s2.h7);
|
||||||
|
return rval;
|
||||||
|
};
|
||||||
|
|
||||||
|
return md;
|
||||||
|
};
|
||||||
|
|
||||||
|
// sha-256 padding bytes not initialized yet
|
||||||
|
var _padding = null;
|
||||||
|
var _initialized = false;
|
||||||
|
|
||||||
|
// table of constants
|
||||||
|
var _k = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the constant tables.
|
||||||
|
*/
|
||||||
|
function _init() {
|
||||||
|
// create padding
|
||||||
|
_padding = String.fromCharCode(128);
|
||||||
|
_padding += forge.util.fillString(String.fromCharCode(0x00), 64);
|
||||||
|
|
||||||
|
// create K table for SHA-256
|
||||||
|
_k = [
|
||||||
|
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
|
||||||
|
0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
|
||||||
|
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
|
||||||
|
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
|
||||||
|
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
|
||||||
|
0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
||||||
|
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
|
||||||
|
0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
|
||||||
|
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
|
||||||
|
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
|
||||||
|
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
|
||||||
|
0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
||||||
|
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
|
||||||
|
0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
|
||||||
|
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
|
||||||
|
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2];
|
||||||
|
|
||||||
|
// now initialized
|
||||||
|
_initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates a SHA-256 state with the given byte buffer.
|
||||||
|
*
|
||||||
|
* @param s the SHA-256 state to update.
|
||||||
|
* @param w the array to use to store words.
|
||||||
|
* @param bytes the byte buffer to update with.
|
||||||
|
*/
|
||||||
|
function _update(s, w, bytes) {
|
||||||
|
// consume 512 bit (64 byte) chunks
|
||||||
|
var t1, t2, s0, s1, ch, maj, i, a, b, c, d, e, f, g, h;
|
||||||
|
var len = bytes.length();
|
||||||
|
while(len >= 64) {
|
||||||
|
// the w array will be populated with sixteen 32-bit big-endian words
|
||||||
|
// and then extended into 64 32-bit words according to SHA-256
|
||||||
|
for(i = 0; i < 16; ++i) {
|
||||||
|
w[i] = bytes.getInt32();
|
||||||
|
}
|
||||||
|
for(; i < 64; ++i) {
|
||||||
|
// XOR word 2 words ago rot right 17, rot right 19, shft right 10
|
||||||
|
t1 = w[i - 2];
|
||||||
|
t1 =
|
||||||
|
((t1 >>> 17) | (t1 << 15)) ^
|
||||||
|
((t1 >>> 19) | (t1 << 13)) ^
|
||||||
|
(t1 >>> 10);
|
||||||
|
// XOR word 15 words ago rot right 7, rot right 18, shft right 3
|
||||||
|
t2 = w[i - 15];
|
||||||
|
t2 =
|
||||||
|
((t2 >>> 7) | (t2 << 25)) ^
|
||||||
|
((t2 >>> 18) | (t2 << 14)) ^
|
||||||
|
(t2 >>> 3);
|
||||||
|
// sum(t1, word 7 ago, t2, word 16 ago) modulo 2^32
|
||||||
|
w[i] = (t1 + w[i - 7] + t2 + w[i - 16]) | 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// initialize hash value for this chunk
|
||||||
|
a = s.h0;
|
||||||
|
b = s.h1;
|
||||||
|
c = s.h2;
|
||||||
|
d = s.h3;
|
||||||
|
e = s.h4;
|
||||||
|
f = s.h5;
|
||||||
|
g = s.h6;
|
||||||
|
h = s.h7;
|
||||||
|
|
||||||
|
// round function
|
||||||
|
for(i = 0; i < 64; ++i) {
|
||||||
|
// Sum1(e)
|
||||||
|
s1 =
|
||||||
|
((e >>> 6) | (e << 26)) ^
|
||||||
|
((e >>> 11) | (e << 21)) ^
|
||||||
|
((e >>> 25) | (e << 7));
|
||||||
|
// Ch(e, f, g) (optimized the same way as SHA-1)
|
||||||
|
ch = g ^ (e & (f ^ g));
|
||||||
|
// Sum0(a)
|
||||||
|
s0 =
|
||||||
|
((a >>> 2) | (a << 30)) ^
|
||||||
|
((a >>> 13) | (a << 19)) ^
|
||||||
|
((a >>> 22) | (a << 10));
|
||||||
|
// Maj(a, b, c) (optimized the same way as SHA-1)
|
||||||
|
maj = (a & b) | (c & (a ^ b));
|
||||||
|
|
||||||
|
// main algorithm
|
||||||
|
t1 = h + s1 + ch + _k[i] + w[i];
|
||||||
|
t2 = s0 + maj;
|
||||||
|
h = g;
|
||||||
|
g = f;
|
||||||
|
f = e;
|
||||||
|
e = (d + t1) | 0;
|
||||||
|
d = c;
|
||||||
|
c = b;
|
||||||
|
b = a;
|
||||||
|
a = (t1 + t2) | 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// update hash state
|
||||||
|
s.h0 = (s.h0 + a) | 0;
|
||||||
|
s.h1 = (s.h1 + b) | 0;
|
||||||
|
s.h2 = (s.h2 + c) | 0;
|
||||||
|
s.h3 = (s.h3 + d) | 0;
|
||||||
|
s.h4 = (s.h4 + e) | 0;
|
||||||
|
s.h5 = (s.h5 + f) | 0;
|
||||||
|
s.h6 = (s.h6 + g) | 0;
|
||||||
|
s.h7 = (s.h7 + h) | 0;
|
||||||
|
len -= 64;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end module implementation
|
||||||
|
|
||||||
|
/* ########## Begin module wrapper ########## */
|
||||||
|
var name = 'sha256';
|
||||||
|
if(typeof define !== 'function') {
|
||||||
|
// NodeJS -> AMD
|
||||||
|
if(typeof module === 'object' && module.exports) {
|
||||||
|
var nodeJS = true;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
factory(require, module);
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
// <script>
|
||||||
|
if(typeof forge === 'undefined') {
|
||||||
|
forge = {};
|
||||||
|
}
|
||||||
|
return initModule(forge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// AMD
|
||||||
|
var deps;
|
||||||
|
var defineFunc = function(require, module) {
|
||||||
|
module.exports = function(forge) {
|
||||||
|
var mods = deps.map(function(dep) {
|
||||||
|
return require(dep);
|
||||||
|
}).concat(initModule);
|
||||||
|
// handle circular dependencies
|
||||||
|
forge = forge || {};
|
||||||
|
forge.defined = forge.defined || {};
|
||||||
|
if(forge.defined[name]) {
|
||||||
|
return forge[name];
|
||||||
|
}
|
||||||
|
forge.defined[name] = true;
|
||||||
|
for(var i = 0; i < mods.length; ++i) {
|
||||||
|
mods[i](forge);
|
||||||
|
}
|
||||||
|
return forge[name];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
var tmpDefine = define;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
|
||||||
|
if(nodeJS) {
|
||||||
|
delete define;
|
||||||
|
return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
}
|
||||||
|
define = tmpDefine;
|
||||||
|
return define.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
};
|
||||||
|
define(['require', 'module', './util'], function() {
|
||||||
|
defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
});
|
||||||
|
})();
|
||||||
603
forge.js/sha512.js
Normal file
@@ -0,0 +1,603 @@
|
|||||||
|
/**
|
||||||
|
* Secure Hash Algorithm with a 1024-bit block size implementation.
|
||||||
|
*
|
||||||
|
* This includes: SHA-512, SHA-384, SHA-512/224, and SHA-512/256. For
|
||||||
|
* SHA-256 (block size 512 bits), see sha256.js.
|
||||||
|
*
|
||||||
|
* See FIPS 180-4 for details.
|
||||||
|
*
|
||||||
|
* @author Dave Longley
|
||||||
|
*
|
||||||
|
* Copyright (c) 2014-2015 Digital Bazaar, Inc.
|
||||||
|
*/
|
||||||
|
(function() {
|
||||||
|
/* ########## Begin module implementation ########## */
|
||||||
|
function initModule(forge) {
|
||||||
|
|
||||||
|
var sha512 = forge.sha512 = forge.sha512 || {};
|
||||||
|
forge.md = forge.md || {};
|
||||||
|
forge.md.algorithms = forge.md.algorithms || {};
|
||||||
|
|
||||||
|
// SHA-512
|
||||||
|
forge.md.sha512 = forge.md.algorithms.sha512 = sha512;
|
||||||
|
|
||||||
|
// SHA-384
|
||||||
|
var sha384 = forge.sha384 = forge.sha512.sha384 = forge.sha512.sha384 || {};
|
||||||
|
sha384.create = function() {
|
||||||
|
return sha512.create('SHA-384');
|
||||||
|
};
|
||||||
|
forge.md.sha384 = forge.md.algorithms.sha384 = sha384;
|
||||||
|
|
||||||
|
// SHA-512/256
|
||||||
|
forge.sha512.sha256 = forge.sha512.sha256 || {
|
||||||
|
create: function() {
|
||||||
|
return sha512.create('SHA-512/256');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
forge.md['sha512/256'] = forge.md.algorithms['sha512/256'] =
|
||||||
|
forge.sha512.sha256;
|
||||||
|
|
||||||
|
// SHA-512/224
|
||||||
|
forge.sha512.sha224 = forge.sha512.sha224 || {
|
||||||
|
create: function() {
|
||||||
|
return sha512.create('SHA-512/224');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
forge.md['sha512/224'] = forge.md.algorithms['sha512/224'] =
|
||||||
|
forge.sha512.sha224;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a SHA-2 message digest object.
|
||||||
|
*
|
||||||
|
* @param algorithm the algorithm to use (SHA-512, SHA-384, SHA-512/224,
|
||||||
|
* SHA-512/256).
|
||||||
|
*
|
||||||
|
* @return a message digest object.
|
||||||
|
*/
|
||||||
|
sha512.create = function(algorithm) {
|
||||||
|
// do initialization as necessary
|
||||||
|
if(!_initialized) {
|
||||||
|
_init();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(typeof algorithm === 'undefined') {
|
||||||
|
algorithm = 'SHA-512';
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!(algorithm in _states)) {
|
||||||
|
throw new Error('Invalid SHA-512 algorithm: ' + algorithm);
|
||||||
|
}
|
||||||
|
|
||||||
|
// SHA-512 state contains eight 64-bit integers (each as two 32-bit ints)
|
||||||
|
var _state = _states[algorithm];
|
||||||
|
var _h = null;
|
||||||
|
|
||||||
|
// input buffer
|
||||||
|
var _input = forge.util.createBuffer();
|
||||||
|
|
||||||
|
// used for 64-bit word storage
|
||||||
|
var _w = new Array(80);
|
||||||
|
for(var wi = 0; wi < 80; ++wi) {
|
||||||
|
_w[wi] = new Array(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// message digest object
|
||||||
|
var md = {
|
||||||
|
// SHA-512 => sha512
|
||||||
|
algorithm: algorithm.replace('-', '').toLowerCase(),
|
||||||
|
blockLength: 128,
|
||||||
|
digestLength: 64,
|
||||||
|
// 56-bit length of message so far (does not including padding)
|
||||||
|
messageLength: 0,
|
||||||
|
// true message length
|
||||||
|
fullMessageLength: null,
|
||||||
|
// size of message length in bytes
|
||||||
|
messageLengthSize: 16
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts the digest.
|
||||||
|
*
|
||||||
|
* @return this digest object.
|
||||||
|
*/
|
||||||
|
md.start = function() {
|
||||||
|
// up to 56-bit message length for convenience
|
||||||
|
md.messageLength = 0;
|
||||||
|
|
||||||
|
// full message length (set md.messageLength128 for backwards-compatibility)
|
||||||
|
md.fullMessageLength = md.messageLength128 = [];
|
||||||
|
var int32s = md.messageLengthSize / 4;
|
||||||
|
for(var i = 0; i < int32s; ++i) {
|
||||||
|
md.fullMessageLength.push(0);
|
||||||
|
}
|
||||||
|
_input = forge.util.createBuffer();
|
||||||
|
_h = new Array(_state.length);
|
||||||
|
for(var i = 0; i < _state.length; ++i) {
|
||||||
|
_h[i] = _state[i].slice(0);
|
||||||
|
}
|
||||||
|
return md;
|
||||||
|
};
|
||||||
|
// start digest automatically for first time
|
||||||
|
md.start();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the digest with the given message input. The given input can
|
||||||
|
* treated as raw input (no encoding will be applied) or an encoding of
|
||||||
|
* 'utf8' maybe given to encode the input using UTF-8.
|
||||||
|
*
|
||||||
|
* @param msg the message input to update with.
|
||||||
|
* @param encoding the encoding to use (default: 'raw', other: 'utf8').
|
||||||
|
*
|
||||||
|
* @return this digest object.
|
||||||
|
*/
|
||||||
|
md.update = function(msg, encoding) {
|
||||||
|
if(encoding === 'utf8') {
|
||||||
|
msg = forge.util.encodeUtf8(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
// update message length
|
||||||
|
var len = msg.length;
|
||||||
|
md.messageLength += len;
|
||||||
|
len = [(len / 0x100000000) >>> 0, len >>> 0];
|
||||||
|
for(var i = md.fullMessageLength.length - 1; i >= 0; --i) {
|
||||||
|
md.fullMessageLength[i] += len[1];
|
||||||
|
len[1] = len[0] + ((md.fullMessageLength[i] / 0x100000000) >>> 0);
|
||||||
|
md.fullMessageLength[i] = md.fullMessageLength[i] >>> 0;
|
||||||
|
len[0] = ((len[1] / 0x100000000) >>> 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// add bytes to input buffer
|
||||||
|
_input.putBytes(msg);
|
||||||
|
|
||||||
|
// process bytes
|
||||||
|
_update(_h, _w, _input);
|
||||||
|
|
||||||
|
// compact input buffer every 2K or if empty
|
||||||
|
if(_input.read > 2048 || _input.length() === 0) {
|
||||||
|
_input.compact();
|
||||||
|
}
|
||||||
|
|
||||||
|
return md;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Produces the digest.
|
||||||
|
*
|
||||||
|
* @return a byte buffer containing the digest value.
|
||||||
|
*/
|
||||||
|
md.digest = function() {
|
||||||
|
/* Note: Here we copy the remaining bytes in the input buffer and
|
||||||
|
add the appropriate SHA-512 padding. Then we do the final update
|
||||||
|
on a copy of the state so that if the user wants to get
|
||||||
|
intermediate digests they can do so. */
|
||||||
|
|
||||||
|
/* Determine the number of bytes that must be added to the message
|
||||||
|
to ensure its length is congruent to 896 mod 1024. In other words,
|
||||||
|
the data to be digested must be a multiple of 1024 bits (or 128 bytes).
|
||||||
|
This data includes the message, some padding, and the length of the
|
||||||
|
message. Since the length of the message will be encoded as 16 bytes (128
|
||||||
|
bits), that means that the last segment of the data must have 112 bytes
|
||||||
|
(896 bits) of message and padding. Therefore, the length of the message
|
||||||
|
plus the padding must be congruent to 896 mod 1024 because
|
||||||
|
1024 - 128 = 896.
|
||||||
|
|
||||||
|
In order to fill up the message length it must be filled with
|
||||||
|
padding that begins with 1 bit followed by all 0 bits. Padding
|
||||||
|
must *always* be present, so if the message length is already
|
||||||
|
congruent to 896 mod 1024, then 1024 padding bits must be added. */
|
||||||
|
|
||||||
|
var finalBlock = forge.util.createBuffer();
|
||||||
|
finalBlock.putBytes(_input.bytes());
|
||||||
|
|
||||||
|
// compute remaining size to be digested (include message length size)
|
||||||
|
var remaining = (
|
||||||
|
md.fullMessageLength[md.fullMessageLength.length - 1] +
|
||||||
|
md.messageLengthSize);
|
||||||
|
|
||||||
|
// add padding for overflow blockSize - overflow
|
||||||
|
// _padding starts with 1 byte with first bit is set (byte value 128), then
|
||||||
|
// there may be up to (blockSize - 1) other pad bytes
|
||||||
|
var overflow = remaining & (md.blockLength - 1);
|
||||||
|
finalBlock.putBytes(_padding.substr(0, md.blockLength - overflow));
|
||||||
|
|
||||||
|
// serialize message length in bits in big-endian order; since length
|
||||||
|
// is stored in bytes we multiply by 8 and add carry from next int
|
||||||
|
var messageLength = forge.util.createBuffer();
|
||||||
|
var next, carry;
|
||||||
|
var bits = md.fullMessageLength[0] * 8;
|
||||||
|
for(var i = 0; i < md.fullMessageLength.length; ++i) {
|
||||||
|
next = md.fullMessageLength[i + 1] * 8;
|
||||||
|
carry = (next / 0x100000000) >>> 0;
|
||||||
|
bits += carry;
|
||||||
|
finalBlock.putInt32(bits >>> 0);
|
||||||
|
bits = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
var h = new Array(_h.length);
|
||||||
|
for(var i = 0; i < _h.length; ++i) {
|
||||||
|
h[i] = _h[i].slice(0);
|
||||||
|
}
|
||||||
|
_update(h, _w, finalBlock);
|
||||||
|
var rval = forge.util.createBuffer();
|
||||||
|
var hlen;
|
||||||
|
if(algorithm === 'SHA-512') {
|
||||||
|
hlen = h.length;
|
||||||
|
} else if(algorithm === 'SHA-384') {
|
||||||
|
hlen = h.length - 2;
|
||||||
|
} else {
|
||||||
|
hlen = h.length - 4;
|
||||||
|
}
|
||||||
|
for(var i = 0; i < hlen; ++i) {
|
||||||
|
rval.putInt32(h[i][0]);
|
||||||
|
if(i !== hlen - 1 || algorithm !== 'SHA-512/224') {
|
||||||
|
rval.putInt32(h[i][1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rval;
|
||||||
|
};
|
||||||
|
|
||||||
|
return md;
|
||||||
|
};
|
||||||
|
|
||||||
|
// sha-512 padding bytes not initialized yet
|
||||||
|
var _padding = null;
|
||||||
|
var _initialized = false;
|
||||||
|
|
||||||
|
// table of constants
|
||||||
|
var _k = null;
|
||||||
|
|
||||||
|
// initial hash states
|
||||||
|
var _states = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the constant tables.
|
||||||
|
*/
|
||||||
|
function _init() {
|
||||||
|
// create padding
|
||||||
|
_padding = String.fromCharCode(128);
|
||||||
|
_padding += forge.util.fillString(String.fromCharCode(0x00), 128);
|
||||||
|
|
||||||
|
// create K table for SHA-512
|
||||||
|
_k = [
|
||||||
|
[0x428a2f98, 0xd728ae22], [0x71374491, 0x23ef65cd],
|
||||||
|
[0xb5c0fbcf, 0xec4d3b2f], [0xe9b5dba5, 0x8189dbbc],
|
||||||
|
[0x3956c25b, 0xf348b538], [0x59f111f1, 0xb605d019],
|
||||||
|
[0x923f82a4, 0xaf194f9b], [0xab1c5ed5, 0xda6d8118],
|
||||||
|
[0xd807aa98, 0xa3030242], [0x12835b01, 0x45706fbe],
|
||||||
|
[0x243185be, 0x4ee4b28c], [0x550c7dc3, 0xd5ffb4e2],
|
||||||
|
[0x72be5d74, 0xf27b896f], [0x80deb1fe, 0x3b1696b1],
|
||||||
|
[0x9bdc06a7, 0x25c71235], [0xc19bf174, 0xcf692694],
|
||||||
|
[0xe49b69c1, 0x9ef14ad2], [0xefbe4786, 0x384f25e3],
|
||||||
|
[0x0fc19dc6, 0x8b8cd5b5], [0x240ca1cc, 0x77ac9c65],
|
||||||
|
[0x2de92c6f, 0x592b0275], [0x4a7484aa, 0x6ea6e483],
|
||||||
|
[0x5cb0a9dc, 0xbd41fbd4], [0x76f988da, 0x831153b5],
|
||||||
|
[0x983e5152, 0xee66dfab], [0xa831c66d, 0x2db43210],
|
||||||
|
[0xb00327c8, 0x98fb213f], [0xbf597fc7, 0xbeef0ee4],
|
||||||
|
[0xc6e00bf3, 0x3da88fc2], [0xd5a79147, 0x930aa725],
|
||||||
|
[0x06ca6351, 0xe003826f], [0x14292967, 0x0a0e6e70],
|
||||||
|
[0x27b70a85, 0x46d22ffc], [0x2e1b2138, 0x5c26c926],
|
||||||
|
[0x4d2c6dfc, 0x5ac42aed], [0x53380d13, 0x9d95b3df],
|
||||||
|
[0x650a7354, 0x8baf63de], [0x766a0abb, 0x3c77b2a8],
|
||||||
|
[0x81c2c92e, 0x47edaee6], [0x92722c85, 0x1482353b],
|
||||||
|
[0xa2bfe8a1, 0x4cf10364], [0xa81a664b, 0xbc423001],
|
||||||
|
[0xc24b8b70, 0xd0f89791], [0xc76c51a3, 0x0654be30],
|
||||||
|
[0xd192e819, 0xd6ef5218], [0xd6990624, 0x5565a910],
|
||||||
|
[0xf40e3585, 0x5771202a], [0x106aa070, 0x32bbd1b8],
|
||||||
|
[0x19a4c116, 0xb8d2d0c8], [0x1e376c08, 0x5141ab53],
|
||||||
|
[0x2748774c, 0xdf8eeb99], [0x34b0bcb5, 0xe19b48a8],
|
||||||
|
[0x391c0cb3, 0xc5c95a63], [0x4ed8aa4a, 0xe3418acb],
|
||||||
|
[0x5b9cca4f, 0x7763e373], [0x682e6ff3, 0xd6b2b8a3],
|
||||||
|
[0x748f82ee, 0x5defb2fc], [0x78a5636f, 0x43172f60],
|
||||||
|
[0x84c87814, 0xa1f0ab72], [0x8cc70208, 0x1a6439ec],
|
||||||
|
[0x90befffa, 0x23631e28], [0xa4506ceb, 0xde82bde9],
|
||||||
|
[0xbef9a3f7, 0xb2c67915], [0xc67178f2, 0xe372532b],
|
||||||
|
[0xca273ece, 0xea26619c], [0xd186b8c7, 0x21c0c207],
|
||||||
|
[0xeada7dd6, 0xcde0eb1e], [0xf57d4f7f, 0xee6ed178],
|
||||||
|
[0x06f067aa, 0x72176fba], [0x0a637dc5, 0xa2c898a6],
|
||||||
|
[0x113f9804, 0xbef90dae], [0x1b710b35, 0x131c471b],
|
||||||
|
[0x28db77f5, 0x23047d84], [0x32caab7b, 0x40c72493],
|
||||||
|
[0x3c9ebe0a, 0x15c9bebc], [0x431d67c4, 0x9c100d4c],
|
||||||
|
[0x4cc5d4be, 0xcb3e42b6], [0x597f299c, 0xfc657e2a],
|
||||||
|
[0x5fcb6fab, 0x3ad6faec], [0x6c44198c, 0x4a475817]
|
||||||
|
];
|
||||||
|
|
||||||
|
// initial hash states
|
||||||
|
_states = {};
|
||||||
|
_states['SHA-512'] = [
|
||||||
|
[0x6a09e667, 0xf3bcc908],
|
||||||
|
[0xbb67ae85, 0x84caa73b],
|
||||||
|
[0x3c6ef372, 0xfe94f82b],
|
||||||
|
[0xa54ff53a, 0x5f1d36f1],
|
||||||
|
[0x510e527f, 0xade682d1],
|
||||||
|
[0x9b05688c, 0x2b3e6c1f],
|
||||||
|
[0x1f83d9ab, 0xfb41bd6b],
|
||||||
|
[0x5be0cd19, 0x137e2179]
|
||||||
|
];
|
||||||
|
_states['SHA-384'] = [
|
||||||
|
[0xcbbb9d5d, 0xc1059ed8],
|
||||||
|
[0x629a292a, 0x367cd507],
|
||||||
|
[0x9159015a, 0x3070dd17],
|
||||||
|
[0x152fecd8, 0xf70e5939],
|
||||||
|
[0x67332667, 0xffc00b31],
|
||||||
|
[0x8eb44a87, 0x68581511],
|
||||||
|
[0xdb0c2e0d, 0x64f98fa7],
|
||||||
|
[0x47b5481d, 0xbefa4fa4]
|
||||||
|
];
|
||||||
|
_states['SHA-512/256'] = [
|
||||||
|
[0x22312194, 0xFC2BF72C],
|
||||||
|
[0x9F555FA3, 0xC84C64C2],
|
||||||
|
[0x2393B86B, 0x6F53B151],
|
||||||
|
[0x96387719, 0x5940EABD],
|
||||||
|
[0x96283EE2, 0xA88EFFE3],
|
||||||
|
[0xBE5E1E25, 0x53863992],
|
||||||
|
[0x2B0199FC, 0x2C85B8AA],
|
||||||
|
[0x0EB72DDC, 0x81C52CA2]
|
||||||
|
];
|
||||||
|
_states['SHA-512/224'] = [
|
||||||
|
[0x8C3D37C8, 0x19544DA2],
|
||||||
|
[0x73E19966, 0x89DCD4D6],
|
||||||
|
[0x1DFAB7AE, 0x32FF9C82],
|
||||||
|
[0x679DD514, 0x582F9FCF],
|
||||||
|
[0x0F6D2B69, 0x7BD44DA8],
|
||||||
|
[0x77E36F73, 0x04C48942],
|
||||||
|
[0x3F9D85A8, 0x6A1D36C8],
|
||||||
|
[0x1112E6AD, 0x91D692A1]
|
||||||
|
];
|
||||||
|
|
||||||
|
// now initialized
|
||||||
|
_initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates a SHA-512 state with the given byte buffer.
|
||||||
|
*
|
||||||
|
* @param s the SHA-512 state to update.
|
||||||
|
* @param w the array to use to store words.
|
||||||
|
* @param bytes the byte buffer to update with.
|
||||||
|
*/
|
||||||
|
function _update(s, w, bytes) {
|
||||||
|
// consume 512 bit (128 byte) chunks
|
||||||
|
var t1_hi, t1_lo;
|
||||||
|
var t2_hi, t2_lo;
|
||||||
|
var s0_hi, s0_lo;
|
||||||
|
var s1_hi, s1_lo;
|
||||||
|
var ch_hi, ch_lo;
|
||||||
|
var maj_hi, maj_lo;
|
||||||
|
var a_hi, a_lo;
|
||||||
|
var b_hi, b_lo;
|
||||||
|
var c_hi, c_lo;
|
||||||
|
var d_hi, d_lo;
|
||||||
|
var e_hi, e_lo;
|
||||||
|
var f_hi, f_lo;
|
||||||
|
var g_hi, g_lo;
|
||||||
|
var h_hi, h_lo;
|
||||||
|
var i, hi, lo, w2, w7, w15, w16;
|
||||||
|
var len = bytes.length();
|
||||||
|
while(len >= 128) {
|
||||||
|
// the w array will be populated with sixteen 64-bit big-endian words
|
||||||
|
// and then extended into 64 64-bit words according to SHA-512
|
||||||
|
for(i = 0; i < 16; ++i) {
|
||||||
|
w[i][0] = bytes.getInt32() >>> 0;
|
||||||
|
w[i][1] = bytes.getInt32() >>> 0;
|
||||||
|
}
|
||||||
|
for(; i < 80; ++i) {
|
||||||
|
// for word 2 words ago: ROTR 19(x) ^ ROTR 61(x) ^ SHR 6(x)
|
||||||
|
w2 = w[i - 2];
|
||||||
|
hi = w2[0];
|
||||||
|
lo = w2[1];
|
||||||
|
|
||||||
|
// high bits
|
||||||
|
t1_hi = (
|
||||||
|
((hi >>> 19) | (lo << 13)) ^ // ROTR 19
|
||||||
|
((lo >>> 29) | (hi << 3)) ^ // ROTR 61/(swap + ROTR 29)
|
||||||
|
(hi >>> 6)) >>> 0; // SHR 6
|
||||||
|
// low bits
|
||||||
|
t1_lo = (
|
||||||
|
((hi << 13) | (lo >>> 19)) ^ // ROTR 19
|
||||||
|
((lo << 3) | (hi >>> 29)) ^ // ROTR 61/(swap + ROTR 29)
|
||||||
|
((hi << 26) | (lo >>> 6))) >>> 0; // SHR 6
|
||||||
|
|
||||||
|
// for word 15 words ago: ROTR 1(x) ^ ROTR 8(x) ^ SHR 7(x)
|
||||||
|
w15 = w[i - 15];
|
||||||
|
hi = w15[0];
|
||||||
|
lo = w15[1];
|
||||||
|
|
||||||
|
// high bits
|
||||||
|
t2_hi = (
|
||||||
|
((hi >>> 1) | (lo << 31)) ^ // ROTR 1
|
||||||
|
((hi >>> 8) | (lo << 24)) ^ // ROTR 8
|
||||||
|
(hi >>> 7)) >>> 0; // SHR 7
|
||||||
|
// low bits
|
||||||
|
t2_lo = (
|
||||||
|
((hi << 31) | (lo >>> 1)) ^ // ROTR 1
|
||||||
|
((hi << 24) | (lo >>> 8)) ^ // ROTR 8
|
||||||
|
((hi << 25) | (lo >>> 7))) >>> 0; // SHR 7
|
||||||
|
|
||||||
|
// sum(t1, word 7 ago, t2, word 16 ago) modulo 2^64 (carry lo overflow)
|
||||||
|
w7 = w[i - 7];
|
||||||
|
w16 = w[i - 16];
|
||||||
|
lo = (t1_lo + w7[1] + t2_lo + w16[1]);
|
||||||
|
w[i][0] = (t1_hi + w7[0] + t2_hi + w16[0] +
|
||||||
|
((lo / 0x100000000) >>> 0)) >>> 0;
|
||||||
|
w[i][1] = lo >>> 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// initialize hash value for this chunk
|
||||||
|
a_hi = s[0][0];
|
||||||
|
a_lo = s[0][1];
|
||||||
|
b_hi = s[1][0];
|
||||||
|
b_lo = s[1][1];
|
||||||
|
c_hi = s[2][0];
|
||||||
|
c_lo = s[2][1];
|
||||||
|
d_hi = s[3][0];
|
||||||
|
d_lo = s[3][1];
|
||||||
|
e_hi = s[4][0];
|
||||||
|
e_lo = s[4][1];
|
||||||
|
f_hi = s[5][0];
|
||||||
|
f_lo = s[5][1];
|
||||||
|
g_hi = s[6][0];
|
||||||
|
g_lo = s[6][1];
|
||||||
|
h_hi = s[7][0];
|
||||||
|
h_lo = s[7][1];
|
||||||
|
|
||||||
|
// round function
|
||||||
|
for(i = 0; i < 80; ++i) {
|
||||||
|
// Sum1(e) = ROTR 14(e) ^ ROTR 18(e) ^ ROTR 41(e)
|
||||||
|
s1_hi = (
|
||||||
|
((e_hi >>> 14) | (e_lo << 18)) ^ // ROTR 14
|
||||||
|
((e_hi >>> 18) | (e_lo << 14)) ^ // ROTR 18
|
||||||
|
((e_lo >>> 9) | (e_hi << 23))) >>> 0; // ROTR 41/(swap + ROTR 9)
|
||||||
|
s1_lo = (
|
||||||
|
((e_hi << 18) | (e_lo >>> 14)) ^ // ROTR 14
|
||||||
|
((e_hi << 14) | (e_lo >>> 18)) ^ // ROTR 18
|
||||||
|
((e_lo << 23) | (e_hi >>> 9))) >>> 0; // ROTR 41/(swap + ROTR 9)
|
||||||
|
|
||||||
|
// Ch(e, f, g) (optimized the same way as SHA-1)
|
||||||
|
ch_hi = (g_hi ^ (e_hi & (f_hi ^ g_hi))) >>> 0;
|
||||||
|
ch_lo = (g_lo ^ (e_lo & (f_lo ^ g_lo))) >>> 0;
|
||||||
|
|
||||||
|
// Sum0(a) = ROTR 28(a) ^ ROTR 34(a) ^ ROTR 39(a)
|
||||||
|
s0_hi = (
|
||||||
|
((a_hi >>> 28) | (a_lo << 4)) ^ // ROTR 28
|
||||||
|
((a_lo >>> 2) | (a_hi << 30)) ^ // ROTR 34/(swap + ROTR 2)
|
||||||
|
((a_lo >>> 7) | (a_hi << 25))) >>> 0; // ROTR 39/(swap + ROTR 7)
|
||||||
|
s0_lo = (
|
||||||
|
((a_hi << 4) | (a_lo >>> 28)) ^ // ROTR 28
|
||||||
|
((a_lo << 30) | (a_hi >>> 2)) ^ // ROTR 34/(swap + ROTR 2)
|
||||||
|
((a_lo << 25) | (a_hi >>> 7))) >>> 0; // ROTR 39/(swap + ROTR 7)
|
||||||
|
|
||||||
|
// Maj(a, b, c) (optimized the same way as SHA-1)
|
||||||
|
maj_hi = ((a_hi & b_hi) | (c_hi & (a_hi ^ b_hi))) >>> 0;
|
||||||
|
maj_lo = ((a_lo & b_lo) | (c_lo & (a_lo ^ b_lo))) >>> 0;
|
||||||
|
|
||||||
|
// main algorithm
|
||||||
|
// t1 = (h + s1 + ch + _k[i] + _w[i]) modulo 2^64 (carry lo overflow)
|
||||||
|
lo = (h_lo + s1_lo + ch_lo + _k[i][1] + w[i][1]);
|
||||||
|
t1_hi = (h_hi + s1_hi + ch_hi + _k[i][0] + w[i][0] +
|
||||||
|
((lo / 0x100000000) >>> 0)) >>> 0;
|
||||||
|
t1_lo = lo >>> 0;
|
||||||
|
|
||||||
|
// t2 = s0 + maj modulo 2^64 (carry lo overflow)
|
||||||
|
lo = s0_lo + maj_lo;
|
||||||
|
t2_hi = (s0_hi + maj_hi + ((lo / 0x100000000) >>> 0)) >>> 0;
|
||||||
|
t2_lo = lo >>> 0;
|
||||||
|
|
||||||
|
h_hi = g_hi;
|
||||||
|
h_lo = g_lo;
|
||||||
|
|
||||||
|
g_hi = f_hi;
|
||||||
|
g_lo = f_lo;
|
||||||
|
|
||||||
|
f_hi = e_hi;
|
||||||
|
f_lo = e_lo;
|
||||||
|
|
||||||
|
// e = (d + t1) modulo 2^64 (carry lo overflow)
|
||||||
|
lo = d_lo + t1_lo;
|
||||||
|
e_hi = (d_hi + t1_hi + ((lo / 0x100000000) >>> 0)) >>> 0;
|
||||||
|
e_lo = lo >>> 0;
|
||||||
|
|
||||||
|
d_hi = c_hi;
|
||||||
|
d_lo = c_lo;
|
||||||
|
|
||||||
|
c_hi = b_hi;
|
||||||
|
c_lo = b_lo;
|
||||||
|
|
||||||
|
b_hi = a_hi;
|
||||||
|
b_lo = a_lo;
|
||||||
|
|
||||||
|
// a = (t1 + t2) modulo 2^64 (carry lo overflow)
|
||||||
|
lo = t1_lo + t2_lo;
|
||||||
|
a_hi = (t1_hi + t2_hi + ((lo / 0x100000000) >>> 0)) >>> 0;
|
||||||
|
a_lo = lo >>> 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// update hash state (additional modulo 2^64)
|
||||||
|
lo = s[0][1] + a_lo;
|
||||||
|
s[0][0] = (s[0][0] + a_hi + ((lo / 0x100000000) >>> 0)) >>> 0;
|
||||||
|
s[0][1] = lo >>> 0;
|
||||||
|
|
||||||
|
lo = s[1][1] + b_lo;
|
||||||
|
s[1][0] = (s[1][0] + b_hi + ((lo / 0x100000000) >>> 0)) >>> 0;
|
||||||
|
s[1][1] = lo >>> 0;
|
||||||
|
|
||||||
|
lo = s[2][1] + c_lo;
|
||||||
|
s[2][0] = (s[2][0] + c_hi + ((lo / 0x100000000) >>> 0)) >>> 0;
|
||||||
|
s[2][1] = lo >>> 0;
|
||||||
|
|
||||||
|
lo = s[3][1] + d_lo;
|
||||||
|
s[3][0] = (s[3][0] + d_hi + ((lo / 0x100000000) >>> 0)) >>> 0;
|
||||||
|
s[3][1] = lo >>> 0;
|
||||||
|
|
||||||
|
lo = s[4][1] + e_lo;
|
||||||
|
s[4][0] = (s[4][0] + e_hi + ((lo / 0x100000000) >>> 0)) >>> 0;
|
||||||
|
s[4][1] = lo >>> 0;
|
||||||
|
|
||||||
|
lo = s[5][1] + f_lo;
|
||||||
|
s[5][0] = (s[5][0] + f_hi + ((lo / 0x100000000) >>> 0)) >>> 0;
|
||||||
|
s[5][1] = lo >>> 0;
|
||||||
|
|
||||||
|
lo = s[6][1] + g_lo;
|
||||||
|
s[6][0] = (s[6][0] + g_hi + ((lo / 0x100000000) >>> 0)) >>> 0;
|
||||||
|
s[6][1] = lo >>> 0;
|
||||||
|
|
||||||
|
lo = s[7][1] + h_lo;
|
||||||
|
s[7][0] = (s[7][0] + h_hi + ((lo / 0x100000000) >>> 0)) >>> 0;
|
||||||
|
s[7][1] = lo >>> 0;
|
||||||
|
|
||||||
|
len -= 128;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end module implementation
|
||||||
|
|
||||||
|
/* ########## Begin module wrapper ########## */
|
||||||
|
var name = 'sha512';
|
||||||
|
if(typeof define !== 'function') {
|
||||||
|
// NodeJS -> AMD
|
||||||
|
if(typeof module === 'object' && module.exports) {
|
||||||
|
var nodeJS = true;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
factory(require, module);
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
// <script>
|
||||||
|
if(typeof forge === 'undefined') {
|
||||||
|
forge = {};
|
||||||
|
}
|
||||||
|
return initModule(forge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// AMD
|
||||||
|
var deps;
|
||||||
|
var defineFunc = function(require, module) {
|
||||||
|
module.exports = function(forge) {
|
||||||
|
var mods = deps.map(function(dep) {
|
||||||
|
return require(dep);
|
||||||
|
}).concat(initModule);
|
||||||
|
// handle circular dependencies
|
||||||
|
forge = forge || {};
|
||||||
|
forge.defined = forge.defined || {};
|
||||||
|
if(forge.defined[name]) {
|
||||||
|
return forge[name];
|
||||||
|
}
|
||||||
|
forge.defined[name] = true;
|
||||||
|
for(var i = 0; i < mods.length; ++i) {
|
||||||
|
mods[i](forge);
|
||||||
|
}
|
||||||
|
return forge[name];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
var tmpDefine = define;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
|
||||||
|
if(nodeJS) {
|
||||||
|
delete define;
|
||||||
|
return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
}
|
||||||
|
define = tmpDefine;
|
||||||
|
return define.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
};
|
||||||
|
define(['require', 'module', './util'], function() {
|
||||||
|
defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
});
|
||||||
|
})();
|
||||||
342
forge.js/socket.js
Normal file
@@ -0,0 +1,342 @@
|
|||||||
|
/**
|
||||||
|
* Socket implementation that uses flash SocketPool class as a backend.
|
||||||
|
*
|
||||||
|
* @author Dave Longley
|
||||||
|
*
|
||||||
|
* Copyright (c) 2010-2013 Digital Bazaar, Inc.
|
||||||
|
*/
|
||||||
|
(function() {
|
||||||
|
/* ########## Begin module implementation ########## */
|
||||||
|
function initModule(forge) {
|
||||||
|
|
||||||
|
// define net namespace
|
||||||
|
var net = forge.net = forge.net || {};
|
||||||
|
|
||||||
|
// map of flash ID to socket pool
|
||||||
|
net.socketPools = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a flash socket pool.
|
||||||
|
*
|
||||||
|
* @param options:
|
||||||
|
* flashId: the dom ID for the flash object element.
|
||||||
|
* policyPort: the default policy port for sockets, 0 to use the
|
||||||
|
* flash default.
|
||||||
|
* policyUrl: the default policy file URL for sockets (if provided
|
||||||
|
* used instead of a policy port).
|
||||||
|
* msie: true if the browser is msie, false if not.
|
||||||
|
*
|
||||||
|
* @return the created socket pool.
|
||||||
|
*/
|
||||||
|
net.createSocketPool = function(options) {
|
||||||
|
// set default
|
||||||
|
options.msie = options.msie || false;
|
||||||
|
|
||||||
|
// initialize the flash interface
|
||||||
|
var spId = options.flashId;
|
||||||
|
var api = document.getElementById(spId);
|
||||||
|
api.init({marshallExceptions: !options.msie});
|
||||||
|
|
||||||
|
// create socket pool entry
|
||||||
|
var sp = {
|
||||||
|
// ID of the socket pool
|
||||||
|
id: spId,
|
||||||
|
// flash interface
|
||||||
|
flashApi: api,
|
||||||
|
// map of socket ID to sockets
|
||||||
|
sockets: {},
|
||||||
|
// default policy port
|
||||||
|
policyPort: options.policyPort || 0,
|
||||||
|
// default policy URL
|
||||||
|
policyUrl: options.policyUrl || null
|
||||||
|
};
|
||||||
|
net.socketPools[spId] = sp;
|
||||||
|
|
||||||
|
// create event handler, subscribe to flash events
|
||||||
|
if(options.msie === true) {
|
||||||
|
sp.handler = function(e) {
|
||||||
|
if(e.id in sp.sockets) {
|
||||||
|
// get handler function
|
||||||
|
var f;
|
||||||
|
switch(e.type) {
|
||||||
|
case 'connect':
|
||||||
|
f = 'connected';
|
||||||
|
break;
|
||||||
|
case 'close':
|
||||||
|
f = 'closed';
|
||||||
|
break;
|
||||||
|
case 'socketData':
|
||||||
|
f = 'data';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
f = 'error';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* IE calls javascript on the thread of the external object
|
||||||
|
that triggered the event (in this case flash) ... which will
|
||||||
|
either run concurrently with other javascript or pre-empt any
|
||||||
|
running javascript in the middle of its execution (BAD!) ...
|
||||||
|
calling setTimeout() will schedule the javascript to run on
|
||||||
|
the javascript thread and solve this EVIL problem. */
|
||||||
|
setTimeout(function(){sp.sockets[e.id][f](e);}, 0);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
sp.handler = function(e) {
|
||||||
|
if(e.id in sp.sockets) {
|
||||||
|
// get handler function
|
||||||
|
var f;
|
||||||
|
switch(e.type) {
|
||||||
|
case 'connect':
|
||||||
|
f = 'connected';
|
||||||
|
break;
|
||||||
|
case 'close':
|
||||||
|
f = 'closed';
|
||||||
|
break;
|
||||||
|
case 'socketData':
|
||||||
|
f = 'data';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
f = 'error';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
sp.sockets[e.id][f](e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
var handler = 'forge.net.socketPools[\'' + spId + '\'].handler';
|
||||||
|
api.subscribe('connect', handler);
|
||||||
|
api.subscribe('close', handler);
|
||||||
|
api.subscribe('socketData', handler);
|
||||||
|
api.subscribe('ioError', handler);
|
||||||
|
api.subscribe('securityError', handler);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroys a socket pool. The socket pool still needs to be cleaned
|
||||||
|
* up via net.cleanup().
|
||||||
|
*/
|
||||||
|
sp.destroy = function() {
|
||||||
|
delete net.socketPools[options.flashId];
|
||||||
|
for(var id in sp.sockets) {
|
||||||
|
sp.sockets[id].destroy();
|
||||||
|
}
|
||||||
|
sp.sockets = {};
|
||||||
|
api.cleanup();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new socket.
|
||||||
|
*
|
||||||
|
* @param options:
|
||||||
|
* connected: function(event) called when the socket connects.
|
||||||
|
* closed: function(event) called when the socket closes.
|
||||||
|
* data: function(event) called when socket data has arrived,
|
||||||
|
* it can be read from the socket using receive().
|
||||||
|
* error: function(event) called when a socket error occurs.
|
||||||
|
*/
|
||||||
|
sp.createSocket = function(options) {
|
||||||
|
// default to empty options
|
||||||
|
options = options || {};
|
||||||
|
|
||||||
|
// create flash socket
|
||||||
|
var id = api.create();
|
||||||
|
|
||||||
|
// create javascript socket wrapper
|
||||||
|
var socket = {
|
||||||
|
id: id,
|
||||||
|
// set handlers
|
||||||
|
connected: options.connected || function(e){},
|
||||||
|
closed: options.closed || function(e){},
|
||||||
|
data: options.data || function(e){},
|
||||||
|
error: options.error || function(e){}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroys this socket.
|
||||||
|
*/
|
||||||
|
socket.destroy = function() {
|
||||||
|
api.destroy(id);
|
||||||
|
delete sp.sockets[id];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Connects this socket.
|
||||||
|
*
|
||||||
|
* @param options:
|
||||||
|
* host: the host to connect to.
|
||||||
|
* port: the port to connect to.
|
||||||
|
* policyPort: the policy port to use (if non-default), 0 to
|
||||||
|
* use the flash default.
|
||||||
|
* policyUrl: the policy file URL to use (instead of port).
|
||||||
|
*/
|
||||||
|
socket.connect = function(options) {
|
||||||
|
// give precedence to policy URL over policy port
|
||||||
|
// if no policy URL and passed port isn't 0, use default port,
|
||||||
|
// otherwise use 0 for the port
|
||||||
|
var policyUrl = options.policyUrl || null;
|
||||||
|
var policyPort = 0;
|
||||||
|
if(policyUrl === null && options.policyPort !== 0) {
|
||||||
|
policyPort = options.policyPort || sp.policyPort;
|
||||||
|
}
|
||||||
|
api.connect(id, options.host, options.port, policyPort, policyUrl);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Closes this socket.
|
||||||
|
*/
|
||||||
|
socket.close = function() {
|
||||||
|
api.close(id);
|
||||||
|
socket.closed({
|
||||||
|
id: socket.id,
|
||||||
|
type: 'close',
|
||||||
|
bytesAvailable: 0
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if the socket is connected or not.
|
||||||
|
*
|
||||||
|
* @return true if connected, false if not.
|
||||||
|
*/
|
||||||
|
socket.isConnected = function() {
|
||||||
|
return api.isConnected(id);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes bytes to this socket.
|
||||||
|
*
|
||||||
|
* @param bytes the bytes (as a string) to write.
|
||||||
|
*
|
||||||
|
* @return true on success, false on failure.
|
||||||
|
*/
|
||||||
|
socket.send = function(bytes) {
|
||||||
|
return api.send(id, forge.util.encode64(bytes));
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads bytes from this socket (non-blocking). Fewer than the number
|
||||||
|
* of bytes requested may be read if enough bytes are not available.
|
||||||
|
*
|
||||||
|
* This method should be called from the data handler if there are
|
||||||
|
* enough bytes available. To see how many bytes are available, check
|
||||||
|
* the 'bytesAvailable' property on the event in the data handler or
|
||||||
|
* call the bytesAvailable() function on the socket. If the browser is
|
||||||
|
* msie, then the bytesAvailable() function should be used to avoid
|
||||||
|
* race conditions. Otherwise, using the property on the data handler's
|
||||||
|
* event may be quicker.
|
||||||
|
*
|
||||||
|
* @param count the maximum number of bytes to read.
|
||||||
|
*
|
||||||
|
* @return the bytes read (as a string) or null on error.
|
||||||
|
*/
|
||||||
|
socket.receive = function(count) {
|
||||||
|
var rval = api.receive(id, count).rval;
|
||||||
|
return (rval === null) ? null : forge.util.decode64(rval);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the number of bytes available for receiving on the socket.
|
||||||
|
*
|
||||||
|
* @return the number of bytes available for receiving.
|
||||||
|
*/
|
||||||
|
socket.bytesAvailable = function() {
|
||||||
|
return api.getBytesAvailable(id);
|
||||||
|
};
|
||||||
|
|
||||||
|
// store and return socket
|
||||||
|
sp.sockets[id] = socket;
|
||||||
|
return socket;
|
||||||
|
};
|
||||||
|
|
||||||
|
return sp;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroys a flash socket pool.
|
||||||
|
*
|
||||||
|
* @param options:
|
||||||
|
* flashId: the dom ID for the flash object element.
|
||||||
|
*/
|
||||||
|
net.destroySocketPool = function(options) {
|
||||||
|
if(options.flashId in net.socketPools) {
|
||||||
|
var sp = net.socketPools[options.flashId];
|
||||||
|
sp.destroy();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new socket.
|
||||||
|
*
|
||||||
|
* @param options:
|
||||||
|
* flashId: the dom ID for the flash object element.
|
||||||
|
* connected: function(event) called when the socket connects.
|
||||||
|
* closed: function(event) called when the socket closes.
|
||||||
|
* data: function(event) called when socket data has arrived, it
|
||||||
|
* can be read from the socket using receive().
|
||||||
|
* error: function(event) called when a socket error occurs.
|
||||||
|
*
|
||||||
|
* @return the created socket.
|
||||||
|
*/
|
||||||
|
net.createSocket = function(options) {
|
||||||
|
var socket = null;
|
||||||
|
if(options.flashId in net.socketPools) {
|
||||||
|
// get related socket pool
|
||||||
|
var sp = net.socketPools[options.flashId];
|
||||||
|
socket = sp.createSocket(options);
|
||||||
|
}
|
||||||
|
return socket;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // end module implementation
|
||||||
|
|
||||||
|
/* ########## Begin module wrapper ########## */
|
||||||
|
var name = 'net';
|
||||||
|
if(typeof define !== 'function') {
|
||||||
|
// NodeJS -> AMD
|
||||||
|
if(typeof module === 'object' && module.exports) {
|
||||||
|
var nodeJS = true;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
factory(require, module);
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
// <script>
|
||||||
|
if(typeof forge === 'undefined') {
|
||||||
|
forge = {};
|
||||||
|
}
|
||||||
|
return initModule(forge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// AMD
|
||||||
|
var deps;
|
||||||
|
var defineFunc = function(require, module) {
|
||||||
|
module.exports = function(forge) {
|
||||||
|
var mods = deps.map(function(dep) {
|
||||||
|
return require(dep);
|
||||||
|
}).concat(initModule);
|
||||||
|
// handle circular dependencies
|
||||||
|
forge = forge || {};
|
||||||
|
forge.defined = forge.defined || {};
|
||||||
|
if(forge.defined[name]) {
|
||||||
|
return forge[name];
|
||||||
|
}
|
||||||
|
forge.defined[name] = true;
|
||||||
|
for(var i = 0; i < mods.length; ++i) {
|
||||||
|
mods[i](forge);
|
||||||
|
}
|
||||||
|
return forge[name];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
var tmpDefine = define;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
|
||||||
|
if(nodeJS) {
|
||||||
|
delete define;
|
||||||
|
return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
}
|
||||||
|
define = tmpDefine;
|
||||||
|
return define.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
};
|
||||||
|
define(['require', 'module'], function() {
|
||||||
|
defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
});
|
||||||
|
})();
|
||||||
295
forge.js/ssh.js
Normal file
@@ -0,0 +1,295 @@
|
|||||||
|
/**
|
||||||
|
* Functions to output keys in SSH-friendly formats.
|
||||||
|
*
|
||||||
|
* This is part of the Forge project which may be used under the terms of
|
||||||
|
* either the BSD License or the GNU General Public License (GPL) Version 2.
|
||||||
|
*
|
||||||
|
* See: https://github.com/digitalbazaar/forge/blob/cbebca3780658703d925b61b2caffb1d263a6c1d/LICENSE
|
||||||
|
*
|
||||||
|
* @author https://github.com/shellac
|
||||||
|
*/
|
||||||
|
(function() {
|
||||||
|
/* ########## Begin module implementation ########## */
|
||||||
|
function initModule(forge) {
|
||||||
|
|
||||||
|
var ssh = forge.ssh = forge.ssh || {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encodes (and optionally encrypts) a private RSA key as a Putty PPK file.
|
||||||
|
*
|
||||||
|
* @param privateKey the key.
|
||||||
|
* @param passphrase a passphrase to protect the key (falsy for no encryption).
|
||||||
|
* @param comment a comment to include in the key file.
|
||||||
|
*
|
||||||
|
* @return the PPK file as a string.
|
||||||
|
*/
|
||||||
|
ssh.privateKeyToPutty = function(privateKey, passphrase, comment) {
|
||||||
|
comment = comment || '';
|
||||||
|
passphrase = passphrase || '';
|
||||||
|
var algorithm = 'ssh-rsa';
|
||||||
|
var encryptionAlgorithm = (passphrase === '') ? 'none' : 'aes256-cbc';
|
||||||
|
|
||||||
|
var ppk = 'PuTTY-User-Key-File-2: ' + algorithm + '\r\n';
|
||||||
|
ppk += 'Encryption: ' + encryptionAlgorithm + '\r\n';
|
||||||
|
ppk += 'Comment: ' + comment + '\r\n';
|
||||||
|
|
||||||
|
// public key into buffer for ppk
|
||||||
|
var pubbuffer = forge.util.createBuffer();
|
||||||
|
_addStringToBuffer(pubbuffer, algorithm);
|
||||||
|
_addBigIntegerToBuffer(pubbuffer, privateKey.e);
|
||||||
|
_addBigIntegerToBuffer(pubbuffer, privateKey.n);
|
||||||
|
|
||||||
|
// write public key
|
||||||
|
var pub = forge.util.encode64(pubbuffer.bytes(), 64);
|
||||||
|
var length = Math.floor(pub.length / 66) + 1; // 66 = 64 + \r\n
|
||||||
|
ppk += 'Public-Lines: ' + length + '\r\n';
|
||||||
|
ppk += pub;
|
||||||
|
|
||||||
|
// private key into a buffer
|
||||||
|
var privbuffer = forge.util.createBuffer();
|
||||||
|
_addBigIntegerToBuffer(privbuffer, privateKey.d);
|
||||||
|
_addBigIntegerToBuffer(privbuffer, privateKey.p);
|
||||||
|
_addBigIntegerToBuffer(privbuffer, privateKey.q);
|
||||||
|
_addBigIntegerToBuffer(privbuffer, privateKey.qInv);
|
||||||
|
|
||||||
|
// optionally encrypt the private key
|
||||||
|
var priv;
|
||||||
|
if(!passphrase) {
|
||||||
|
// use the unencrypted buffer
|
||||||
|
priv = forge.util.encode64(privbuffer.bytes(), 64);
|
||||||
|
} else {
|
||||||
|
// encrypt RSA key using passphrase
|
||||||
|
var encLen = privbuffer.length() + 16 - 1;
|
||||||
|
encLen -= encLen % 16;
|
||||||
|
|
||||||
|
// pad private key with sha1-d data -- needs to be a multiple of 16
|
||||||
|
var padding = _sha1(privbuffer.bytes());
|
||||||
|
|
||||||
|
padding.truncate(padding.length() - encLen + privbuffer.length());
|
||||||
|
privbuffer.putBuffer(padding);
|
||||||
|
|
||||||
|
var aeskey = forge.util.createBuffer();
|
||||||
|
aeskey.putBuffer(_sha1('\x00\x00\x00\x00', passphrase));
|
||||||
|
aeskey.putBuffer(_sha1('\x00\x00\x00\x01', passphrase));
|
||||||
|
|
||||||
|
// encrypt some bytes using CBC mode
|
||||||
|
// key is 40 bytes, so truncate *by* 8 bytes
|
||||||
|
var cipher = forge.aes.createEncryptionCipher(aeskey.truncate(8), 'CBC');
|
||||||
|
cipher.start(forge.util.createBuffer().fillWithByte(0, 16));
|
||||||
|
cipher.update(privbuffer.copy());
|
||||||
|
cipher.finish();
|
||||||
|
var encrypted = cipher.output;
|
||||||
|
|
||||||
|
// Note: this appears to differ from Putty -- is forge wrong, or putty?
|
||||||
|
// due to padding we finish as an exact multiple of 16
|
||||||
|
encrypted.truncate(16); // all padding
|
||||||
|
|
||||||
|
priv = forge.util.encode64(encrypted.bytes(), 64);
|
||||||
|
}
|
||||||
|
|
||||||
|
// output private key
|
||||||
|
length = Math.floor(priv.length / 66) + 1; // 64 + \r\n
|
||||||
|
ppk += '\r\nPrivate-Lines: ' + length + '\r\n';
|
||||||
|
ppk += priv;
|
||||||
|
|
||||||
|
// MAC
|
||||||
|
var mackey = _sha1('putty-private-key-file-mac-key', passphrase);
|
||||||
|
|
||||||
|
var macbuffer = forge.util.createBuffer();
|
||||||
|
_addStringToBuffer(macbuffer, algorithm);
|
||||||
|
_addStringToBuffer(macbuffer, encryptionAlgorithm);
|
||||||
|
_addStringToBuffer(macbuffer, comment);
|
||||||
|
macbuffer.putInt32(pubbuffer.length());
|
||||||
|
macbuffer.putBuffer(pubbuffer);
|
||||||
|
macbuffer.putInt32(privbuffer.length());
|
||||||
|
macbuffer.putBuffer(privbuffer);
|
||||||
|
|
||||||
|
var hmac = forge.hmac.create();
|
||||||
|
hmac.start('sha1', mackey);
|
||||||
|
hmac.update(macbuffer.bytes());
|
||||||
|
|
||||||
|
ppk += '\r\nPrivate-MAC: ' + hmac.digest().toHex() + '\r\n';
|
||||||
|
|
||||||
|
return ppk;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encodes a public RSA key as an OpenSSH file.
|
||||||
|
*
|
||||||
|
* @param key the key.
|
||||||
|
* @param comment a comment.
|
||||||
|
*
|
||||||
|
* @return the public key in OpenSSH format.
|
||||||
|
*/
|
||||||
|
ssh.publicKeyToOpenSSH = function(key, comment) {
|
||||||
|
var type = 'ssh-rsa';
|
||||||
|
comment = comment || '';
|
||||||
|
|
||||||
|
var buffer = forge.util.createBuffer();
|
||||||
|
_addStringToBuffer(buffer, type);
|
||||||
|
_addBigIntegerToBuffer(buffer, key.e);
|
||||||
|
_addBigIntegerToBuffer(buffer, key.n);
|
||||||
|
|
||||||
|
return type + ' ' + forge.util.encode64(buffer.bytes()) + ' ' + comment;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encodes a private RSA key as an OpenSSH file.
|
||||||
|
*
|
||||||
|
* @param key the key.
|
||||||
|
* @param passphrase a passphrase to protect the key (falsy for no encryption).
|
||||||
|
*
|
||||||
|
* @return the public key in OpenSSH format.
|
||||||
|
*/
|
||||||
|
ssh.privateKeyToOpenSSH = function(privateKey, passphrase) {
|
||||||
|
if(!passphrase) {
|
||||||
|
return forge.pki.privateKeyToPem(privateKey);
|
||||||
|
}
|
||||||
|
// OpenSSH private key is just a legacy format, it seems
|
||||||
|
return forge.pki.encryptRsaPrivateKey(privateKey, passphrase,
|
||||||
|
{legacy: true, algorithm: 'aes128'});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the SSH fingerprint for the given public key.
|
||||||
|
*
|
||||||
|
* @param options the options to use.
|
||||||
|
* [md] the message digest object to use (defaults to forge.md.md5).
|
||||||
|
* [encoding] an alternative output encoding, such as 'hex'
|
||||||
|
* (defaults to none, outputs a byte buffer).
|
||||||
|
* [delimiter] the delimiter to use between bytes for 'hex' encoded
|
||||||
|
* output, eg: ':' (defaults to none).
|
||||||
|
*
|
||||||
|
* @return the fingerprint as a byte buffer or other encoding based on options.
|
||||||
|
*/
|
||||||
|
ssh.getPublicKeyFingerprint = function(key, options) {
|
||||||
|
options = options || {};
|
||||||
|
var md = options.md || forge.md.md5.create();
|
||||||
|
|
||||||
|
var type = 'ssh-rsa';
|
||||||
|
var buffer = forge.util.createBuffer();
|
||||||
|
_addStringToBuffer(buffer, type);
|
||||||
|
_addBigIntegerToBuffer(buffer, key.e);
|
||||||
|
_addBigIntegerToBuffer(buffer, key.n);
|
||||||
|
|
||||||
|
// hash public key bytes
|
||||||
|
md.start();
|
||||||
|
md.update(buffer.getBytes());
|
||||||
|
var digest = md.digest();
|
||||||
|
if(options.encoding === 'hex') {
|
||||||
|
var hex = digest.toHex();
|
||||||
|
if(options.delimiter) {
|
||||||
|
return hex.match(/.{2}/g).join(options.delimiter);
|
||||||
|
}
|
||||||
|
return hex;
|
||||||
|
} else if(options.encoding === 'binary') {
|
||||||
|
return digest.getBytes();
|
||||||
|
} else if(options.encoding) {
|
||||||
|
throw new Error('Unknown encoding "' + options.encoding + '".');
|
||||||
|
}
|
||||||
|
return digest;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds len(val) then val to a buffer.
|
||||||
|
*
|
||||||
|
* @param buffer the buffer to add to.
|
||||||
|
* @param val a big integer.
|
||||||
|
*/
|
||||||
|
function _addBigIntegerToBuffer(buffer, val) {
|
||||||
|
var hexVal = val.toString(16);
|
||||||
|
// ensure 2s complement +ve
|
||||||
|
if(hexVal[0] >= '8') {
|
||||||
|
hexVal = '00' + hexVal;
|
||||||
|
}
|
||||||
|
var bytes = forge.util.hexToBytes(hexVal);
|
||||||
|
buffer.putInt32(bytes.length);
|
||||||
|
buffer.putBytes(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds len(val) then val to a buffer.
|
||||||
|
*
|
||||||
|
* @param buffer the buffer to add to.
|
||||||
|
* @param val a string.
|
||||||
|
*/
|
||||||
|
function _addStringToBuffer(buffer, val) {
|
||||||
|
buffer.putInt32(val.length);
|
||||||
|
buffer.putString(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hashes the arguments into one value using SHA-1.
|
||||||
|
*
|
||||||
|
* @return the sha1 hash of the provided arguments.
|
||||||
|
*/
|
||||||
|
function _sha1() {
|
||||||
|
var sha = forge.md.sha1.create();
|
||||||
|
var num = arguments.length;
|
||||||
|
for (var i = 0; i < num; ++i) {
|
||||||
|
sha.update(arguments[i]);
|
||||||
|
}
|
||||||
|
return sha.digest();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end module implementation
|
||||||
|
|
||||||
|
/* ########## Begin module wrapper ########## */
|
||||||
|
var name = 'ssh';
|
||||||
|
if(typeof define !== 'function') {
|
||||||
|
// NodeJS -> AMD
|
||||||
|
if(typeof module === 'object' && module.exports) {
|
||||||
|
var nodeJS = true;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
factory(require, module);
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
// <script>
|
||||||
|
if(typeof forge === 'undefined') {
|
||||||
|
forge = {};
|
||||||
|
}
|
||||||
|
return initModule(forge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// AMD
|
||||||
|
var deps;
|
||||||
|
var defineFunc = function(require, module) {
|
||||||
|
module.exports = function(forge) {
|
||||||
|
var mods = deps.map(function(dep) {
|
||||||
|
return require(dep);
|
||||||
|
}).concat(initModule);
|
||||||
|
// handle circular dependencies
|
||||||
|
forge = forge || {};
|
||||||
|
forge.defined = forge.defined || {};
|
||||||
|
if(forge.defined[name]) {
|
||||||
|
return forge[name];
|
||||||
|
}
|
||||||
|
forge.defined[name] = true;
|
||||||
|
for(var i = 0; i < mods.length; ++i) {
|
||||||
|
mods[i](forge);
|
||||||
|
}
|
||||||
|
return forge[name];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
var tmpDefine = define;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
|
||||||
|
if(nodeJS) {
|
||||||
|
delete define;
|
||||||
|
return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
}
|
||||||
|
define = tmpDefine;
|
||||||
|
return define.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
};
|
||||||
|
define([
|
||||||
|
'require',
|
||||||
|
'module',
|
||||||
|
'./aes',
|
||||||
|
'./hmac',
|
||||||
|
'./md5',
|
||||||
|
'./sha1',
|
||||||
|
'./util'
|
||||||
|
], function() {
|
||||||
|
defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
});
|
||||||
|
})();
|
||||||
778
forge.js/task.js
Normal file
@@ -0,0 +1,778 @@
|
|||||||
|
/**
|
||||||
|
* Support for concurrent task management and synchronization in web
|
||||||
|
* applications.
|
||||||
|
*
|
||||||
|
* @author Dave Longley
|
||||||
|
* @author David I. Lehn <dlehn@digitalbazaar.com>
|
||||||
|
*
|
||||||
|
* Copyright (c) 2009-2013 Digital Bazaar, Inc.
|
||||||
|
*/
|
||||||
|
(function() {
|
||||||
|
/* ########## Begin module implementation ########## */
|
||||||
|
function initModule(forge) {
|
||||||
|
|
||||||
|
// logging category
|
||||||
|
var cat = 'forge.task';
|
||||||
|
|
||||||
|
// verbose level
|
||||||
|
// 0: off, 1: a little, 2: a whole lot
|
||||||
|
// Verbose debug logging is surrounded by a level check to avoid the
|
||||||
|
// performance issues with even calling the logging code regardless if it
|
||||||
|
// is actually logged. For performance reasons this should not be set to 2
|
||||||
|
// for production use.
|
||||||
|
// ex: if(sVL >= 2) forge.log.verbose(....)
|
||||||
|
var sVL = 0;
|
||||||
|
|
||||||
|
// track tasks for debugging
|
||||||
|
var sTasks = {};
|
||||||
|
var sNextTaskId = 0;
|
||||||
|
// debug access
|
||||||
|
forge.debug.set(cat, 'tasks', sTasks);
|
||||||
|
|
||||||
|
// a map of task type to task queue
|
||||||
|
var sTaskQueues = {};
|
||||||
|
// debug access
|
||||||
|
forge.debug.set(cat, 'queues', sTaskQueues);
|
||||||
|
|
||||||
|
// name for unnamed tasks
|
||||||
|
var sNoTaskName = '?';
|
||||||
|
|
||||||
|
// maximum number of doNext() recursions before a context swap occurs
|
||||||
|
// FIXME: might need to tweak this based on the browser
|
||||||
|
var sMaxRecursions = 30;
|
||||||
|
|
||||||
|
// time slice for doing tasks before a context swap occurs
|
||||||
|
// FIXME: might need to tweak this based on the browser
|
||||||
|
var sTimeSlice = 20;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Task states.
|
||||||
|
*
|
||||||
|
* READY: ready to start processing
|
||||||
|
* RUNNING: task or a subtask is running
|
||||||
|
* BLOCKED: task is waiting to acquire N permits to continue
|
||||||
|
* SLEEPING: task is sleeping for a period of time
|
||||||
|
* DONE: task is done
|
||||||
|
* ERROR: task has an error
|
||||||
|
*/
|
||||||
|
var READY = 'ready';
|
||||||
|
var RUNNING = 'running';
|
||||||
|
var BLOCKED = 'blocked';
|
||||||
|
var SLEEPING = 'sleeping';
|
||||||
|
var DONE = 'done';
|
||||||
|
var ERROR = 'error';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Task actions. Used to control state transitions.
|
||||||
|
*
|
||||||
|
* STOP: stop processing
|
||||||
|
* START: start processing tasks
|
||||||
|
* BLOCK: block task from continuing until 1 or more permits are released
|
||||||
|
* UNBLOCK: release one or more permits
|
||||||
|
* SLEEP: sleep for a period of time
|
||||||
|
* WAKEUP: wakeup early from SLEEPING state
|
||||||
|
* CANCEL: cancel further tasks
|
||||||
|
* FAIL: a failure occured
|
||||||
|
*/
|
||||||
|
var STOP = 'stop';
|
||||||
|
var START = 'start';
|
||||||
|
var BLOCK = 'block';
|
||||||
|
var UNBLOCK = 'unblock';
|
||||||
|
var SLEEP = 'sleep';
|
||||||
|
var WAKEUP = 'wakeup';
|
||||||
|
var CANCEL = 'cancel';
|
||||||
|
var FAIL = 'fail';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* State transition table.
|
||||||
|
*
|
||||||
|
* nextState = sStateTable[currentState][action]
|
||||||
|
*/
|
||||||
|
var sStateTable = {};
|
||||||
|
|
||||||
|
sStateTable[READY] = {};
|
||||||
|
sStateTable[READY][STOP] = READY;
|
||||||
|
sStateTable[READY][START] = RUNNING;
|
||||||
|
sStateTable[READY][CANCEL] = DONE;
|
||||||
|
sStateTable[READY][FAIL] = ERROR;
|
||||||
|
|
||||||
|
sStateTable[RUNNING] = {};
|
||||||
|
sStateTable[RUNNING][STOP] = READY;
|
||||||
|
sStateTable[RUNNING][START] = RUNNING;
|
||||||
|
sStateTable[RUNNING][BLOCK] = BLOCKED;
|
||||||
|
sStateTable[RUNNING][UNBLOCK] = RUNNING;
|
||||||
|
sStateTable[RUNNING][SLEEP] = SLEEPING;
|
||||||
|
sStateTable[RUNNING][WAKEUP] = RUNNING;
|
||||||
|
sStateTable[RUNNING][CANCEL] = DONE;
|
||||||
|
sStateTable[RUNNING][FAIL] = ERROR;
|
||||||
|
|
||||||
|
sStateTable[BLOCKED] = {};
|
||||||
|
sStateTable[BLOCKED][STOP] = BLOCKED;
|
||||||
|
sStateTable[BLOCKED][START] = BLOCKED;
|
||||||
|
sStateTable[BLOCKED][BLOCK] = BLOCKED;
|
||||||
|
sStateTable[BLOCKED][UNBLOCK] = BLOCKED;
|
||||||
|
sStateTable[BLOCKED][SLEEP] = BLOCKED;
|
||||||
|
sStateTable[BLOCKED][WAKEUP] = BLOCKED;
|
||||||
|
sStateTable[BLOCKED][CANCEL] = DONE;
|
||||||
|
sStateTable[BLOCKED][FAIL] = ERROR;
|
||||||
|
|
||||||
|
sStateTable[SLEEPING] = {};
|
||||||
|
sStateTable[SLEEPING][STOP] = SLEEPING;
|
||||||
|
sStateTable[SLEEPING][START] = SLEEPING;
|
||||||
|
sStateTable[SLEEPING][BLOCK] = SLEEPING;
|
||||||
|
sStateTable[SLEEPING][UNBLOCK] = SLEEPING;
|
||||||
|
sStateTable[SLEEPING][SLEEP] = SLEEPING;
|
||||||
|
sStateTable[SLEEPING][WAKEUP] = SLEEPING;
|
||||||
|
sStateTable[SLEEPING][CANCEL] = DONE;
|
||||||
|
sStateTable[SLEEPING][FAIL] = ERROR;
|
||||||
|
|
||||||
|
sStateTable[DONE] = {};
|
||||||
|
sStateTable[DONE][STOP] = DONE;
|
||||||
|
sStateTable[DONE][START] = DONE;
|
||||||
|
sStateTable[DONE][BLOCK] = DONE;
|
||||||
|
sStateTable[DONE][UNBLOCK] = DONE;
|
||||||
|
sStateTable[DONE][SLEEP] = DONE;
|
||||||
|
sStateTable[DONE][WAKEUP] = DONE;
|
||||||
|
sStateTable[DONE][CANCEL] = DONE;
|
||||||
|
sStateTable[DONE][FAIL] = ERROR;
|
||||||
|
|
||||||
|
sStateTable[ERROR] = {};
|
||||||
|
sStateTable[ERROR][STOP] = ERROR;
|
||||||
|
sStateTable[ERROR][START] = ERROR;
|
||||||
|
sStateTable[ERROR][BLOCK] = ERROR;
|
||||||
|
sStateTable[ERROR][UNBLOCK] = ERROR;
|
||||||
|
sStateTable[ERROR][SLEEP] = ERROR;
|
||||||
|
sStateTable[ERROR][WAKEUP] = ERROR;
|
||||||
|
sStateTable[ERROR][CANCEL] = ERROR;
|
||||||
|
sStateTable[ERROR][FAIL] = ERROR;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new task.
|
||||||
|
*
|
||||||
|
* @param options options for this task
|
||||||
|
* run: the run function for the task (required)
|
||||||
|
* name: the run function for the task (optional)
|
||||||
|
* parent: parent of this task (optional)
|
||||||
|
*
|
||||||
|
* @return the empty task.
|
||||||
|
*/
|
||||||
|
var Task = function(options) {
|
||||||
|
// task id
|
||||||
|
this.id = -1;
|
||||||
|
|
||||||
|
// task name
|
||||||
|
this.name = options.name || sNoTaskName;
|
||||||
|
|
||||||
|
// task has no parent
|
||||||
|
this.parent = options.parent || null;
|
||||||
|
|
||||||
|
// save run function
|
||||||
|
this.run = options.run;
|
||||||
|
|
||||||
|
// create a queue of subtasks to run
|
||||||
|
this.subtasks = [];
|
||||||
|
|
||||||
|
// error flag
|
||||||
|
this.error = false;
|
||||||
|
|
||||||
|
// state of the task
|
||||||
|
this.state = READY;
|
||||||
|
|
||||||
|
// number of times the task has been blocked (also the number
|
||||||
|
// of permits needed to be released to continue running)
|
||||||
|
this.blocks = 0;
|
||||||
|
|
||||||
|
// timeout id when sleeping
|
||||||
|
this.timeoutId = null;
|
||||||
|
|
||||||
|
// no swap time yet
|
||||||
|
this.swapTime = null;
|
||||||
|
|
||||||
|
// no user data
|
||||||
|
this.userData = null;
|
||||||
|
|
||||||
|
// initialize task
|
||||||
|
// FIXME: deal with overflow
|
||||||
|
this.id = sNextTaskId++;
|
||||||
|
sTasks[this.id] = this;
|
||||||
|
if(sVL >= 1) {
|
||||||
|
forge.log.verbose(cat, '[%s][%s] init', this.id, this.name, this);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logs debug information on this task and the system state.
|
||||||
|
*/
|
||||||
|
Task.prototype.debug = function(msg) {
|
||||||
|
msg = msg || '';
|
||||||
|
forge.log.debug(cat, msg,
|
||||||
|
'[%s][%s] task:', this.id, this.name, this,
|
||||||
|
'subtasks:', this.subtasks.length,
|
||||||
|
'queue:', sTaskQueues);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a subtask to run after task.doNext() or task.fail() is called.
|
||||||
|
*
|
||||||
|
* @param name human readable name for this task (optional).
|
||||||
|
* @param subrun a function to run that takes the current task as
|
||||||
|
* its first parameter.
|
||||||
|
*
|
||||||
|
* @return the current task (useful for chaining next() calls).
|
||||||
|
*/
|
||||||
|
Task.prototype.next = function(name, subrun) {
|
||||||
|
// juggle parameters if it looks like no name is given
|
||||||
|
if(typeof(name) === 'function') {
|
||||||
|
subrun = name;
|
||||||
|
|
||||||
|
// inherit parent's name
|
||||||
|
name = this.name;
|
||||||
|
}
|
||||||
|
// create subtask, set parent to this task, propagate callbacks
|
||||||
|
var subtask = new Task({
|
||||||
|
run: subrun,
|
||||||
|
name: name,
|
||||||
|
parent: this
|
||||||
|
});
|
||||||
|
// start subtasks running
|
||||||
|
subtask.state = RUNNING;
|
||||||
|
subtask.type = this.type;
|
||||||
|
subtask.successCallback = this.successCallback || null;
|
||||||
|
subtask.failureCallback = this.failureCallback || null;
|
||||||
|
|
||||||
|
// queue a new subtask
|
||||||
|
this.subtasks.push(subtask);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds subtasks to run in parallel after task.doNext() or task.fail()
|
||||||
|
* is called.
|
||||||
|
*
|
||||||
|
* @param name human readable name for this task (optional).
|
||||||
|
* @param subrun functions to run that take the current task as
|
||||||
|
* their first parameter.
|
||||||
|
*
|
||||||
|
* @return the current task (useful for chaining next() calls).
|
||||||
|
*/
|
||||||
|
Task.prototype.parallel = function(name, subrun) {
|
||||||
|
// juggle parameters if it looks like no name is given
|
||||||
|
if(forge.util.isArray(name)) {
|
||||||
|
subrun = name;
|
||||||
|
|
||||||
|
// inherit parent's name
|
||||||
|
name = this.name;
|
||||||
|
}
|
||||||
|
// Wrap parallel tasks in a regular task so they are started at the
|
||||||
|
// proper time.
|
||||||
|
return this.next(name, function(task) {
|
||||||
|
// block waiting for subtasks
|
||||||
|
var ptask = task;
|
||||||
|
ptask.block(subrun.length);
|
||||||
|
|
||||||
|
// we pass the iterator from the loop below as a parameter
|
||||||
|
// to a function because it is otherwise included in the
|
||||||
|
// closure and changes as the loop changes -- causing i
|
||||||
|
// to always be set to its highest value
|
||||||
|
var startParallelTask = function(pname, pi) {
|
||||||
|
forge.task.start({
|
||||||
|
type: pname,
|
||||||
|
run: function(task) {
|
||||||
|
subrun[pi](task);
|
||||||
|
},
|
||||||
|
success: function(task) {
|
||||||
|
ptask.unblock();
|
||||||
|
},
|
||||||
|
failure: function(task) {
|
||||||
|
ptask.unblock();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
for(var i = 0; i < subrun.length; i++) {
|
||||||
|
// Type must be unique so task starts in parallel:
|
||||||
|
// name + private string + task id + sub-task index
|
||||||
|
// start tasks in parallel and unblock when the finish
|
||||||
|
var pname = name + '__parallel-' + task.id + '-' + i;
|
||||||
|
var pi = i;
|
||||||
|
startParallelTask(pname, pi);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stops a running task.
|
||||||
|
*/
|
||||||
|
Task.prototype.stop = function() {
|
||||||
|
this.state = sStateTable[this.state][STOP];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts running a task.
|
||||||
|
*/
|
||||||
|
Task.prototype.start = function() {
|
||||||
|
this.error = false;
|
||||||
|
this.state = sStateTable[this.state][START];
|
||||||
|
|
||||||
|
// try to restart
|
||||||
|
if(this.state === RUNNING) {
|
||||||
|
this.start = new Date();
|
||||||
|
this.run(this);
|
||||||
|
runNext(this, 0);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Blocks a task until it one or more permits have been released. The
|
||||||
|
* task will not resume until the requested number of permits have
|
||||||
|
* been released with call(s) to unblock().
|
||||||
|
*
|
||||||
|
* @param n number of permits to wait for(default: 1).
|
||||||
|
*/
|
||||||
|
Task.prototype.block = function(n) {
|
||||||
|
n = typeof(n) === 'undefined' ? 1 : n;
|
||||||
|
this.blocks += n;
|
||||||
|
if(this.blocks > 0) {
|
||||||
|
this.state = sStateTable[this.state][BLOCK];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Releases a permit to unblock a task. If a task was blocked by
|
||||||
|
* requesting N permits via block(), then it will only continue
|
||||||
|
* running once enough permits have been released via unblock() calls.
|
||||||
|
*
|
||||||
|
* If multiple processes need to synchronize with a single task then
|
||||||
|
* use a condition variable (see forge.task.createCondition). It is
|
||||||
|
* an error to unblock a task more times than it has been blocked.
|
||||||
|
*
|
||||||
|
* @param n number of permits to release (default: 1).
|
||||||
|
*
|
||||||
|
* @return the current block count (task is unblocked when count is 0)
|
||||||
|
*/
|
||||||
|
Task.prototype.unblock = function(n) {
|
||||||
|
n = typeof(n) === 'undefined' ? 1 : n;
|
||||||
|
this.blocks -= n;
|
||||||
|
if(this.blocks === 0 && this.state !== DONE) {
|
||||||
|
this.state = RUNNING;
|
||||||
|
runNext(this, 0);
|
||||||
|
}
|
||||||
|
return this.blocks;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sleep for a period of time before resuming tasks.
|
||||||
|
*
|
||||||
|
* @param n number of milliseconds to sleep (default: 0).
|
||||||
|
*/
|
||||||
|
Task.prototype.sleep = function(n) {
|
||||||
|
n = typeof(n) === 'undefined' ? 0 : n;
|
||||||
|
this.state = sStateTable[this.state][SLEEP];
|
||||||
|
var self = this;
|
||||||
|
this.timeoutId = setTimeout(function() {
|
||||||
|
self.timeoutId = null;
|
||||||
|
self.state = RUNNING;
|
||||||
|
runNext(self, 0);
|
||||||
|
}, n);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Waits on a condition variable until notified. The next task will
|
||||||
|
* not be scheduled until notification. A condition variable can be
|
||||||
|
* created with forge.task.createCondition().
|
||||||
|
*
|
||||||
|
* Once cond.notify() is called, the task will continue.
|
||||||
|
*
|
||||||
|
* @param cond the condition variable to wait on.
|
||||||
|
*/
|
||||||
|
Task.prototype.wait = function(cond) {
|
||||||
|
cond.wait(this);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If sleeping, wakeup and continue running tasks.
|
||||||
|
*/
|
||||||
|
Task.prototype.wakeup = function() {
|
||||||
|
if(this.state === SLEEPING) {
|
||||||
|
cancelTimeout(this.timeoutId);
|
||||||
|
this.timeoutId = null;
|
||||||
|
this.state = RUNNING;
|
||||||
|
runNext(this, 0);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancel all remaining subtasks of this task.
|
||||||
|
*/
|
||||||
|
Task.prototype.cancel = function() {
|
||||||
|
this.state = sStateTable[this.state][CANCEL];
|
||||||
|
// remove permits needed
|
||||||
|
this.permitsNeeded = 0;
|
||||||
|
// cancel timeouts
|
||||||
|
if(this.timeoutId !== null) {
|
||||||
|
cancelTimeout(this.timeoutId);
|
||||||
|
this.timeoutId = null;
|
||||||
|
}
|
||||||
|
// remove subtasks
|
||||||
|
this.subtasks = [];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finishes this task with failure and sets error flag. The entire
|
||||||
|
* task will be aborted unless the next task that should execute
|
||||||
|
* is passed as a parameter. This allows levels of subtasks to be
|
||||||
|
* skipped. For instance, to abort only this tasks's subtasks, then
|
||||||
|
* call fail(task.parent). To abort this task's subtasks and its
|
||||||
|
* parent's subtasks, call fail(task.parent.parent). To abort
|
||||||
|
* all tasks and simply call the task callback, call fail() or
|
||||||
|
* fail(null).
|
||||||
|
*
|
||||||
|
* The task callback (success or failure) will always, eventually, be
|
||||||
|
* called.
|
||||||
|
*
|
||||||
|
* @param next the task to continue at, or null to abort entirely.
|
||||||
|
*/
|
||||||
|
Task.prototype.fail = function(next) {
|
||||||
|
// set error flag
|
||||||
|
this.error = true;
|
||||||
|
|
||||||
|
// finish task
|
||||||
|
finish(this, true);
|
||||||
|
|
||||||
|
if(next) {
|
||||||
|
// propagate task info
|
||||||
|
next.error = this.error;
|
||||||
|
next.swapTime = this.swapTime;
|
||||||
|
next.userData = this.userData;
|
||||||
|
|
||||||
|
// do next task as specified
|
||||||
|
runNext(next, 0);
|
||||||
|
} else {
|
||||||
|
if(this.parent !== null) {
|
||||||
|
// finish root task (ensures it is removed from task queue)
|
||||||
|
var parent = this.parent;
|
||||||
|
while(parent.parent !== null) {
|
||||||
|
// propagate task info
|
||||||
|
parent.error = this.error;
|
||||||
|
parent.swapTime = this.swapTime;
|
||||||
|
parent.userData = this.userData;
|
||||||
|
parent = parent.parent;
|
||||||
|
}
|
||||||
|
finish(parent, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// call failure callback if one exists
|
||||||
|
if(this.failureCallback) {
|
||||||
|
this.failureCallback(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asynchronously start a task.
|
||||||
|
*
|
||||||
|
* @param task the task to start.
|
||||||
|
*/
|
||||||
|
var start = function(task) {
|
||||||
|
task.error = false;
|
||||||
|
task.state = sStateTable[task.state][START];
|
||||||
|
setTimeout(function() {
|
||||||
|
if(task.state === RUNNING) {
|
||||||
|
task.swapTime = +new Date();
|
||||||
|
task.run(task);
|
||||||
|
runNext(task, 0);
|
||||||
|
}
|
||||||
|
}, 0);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run the next subtask or finish this task.
|
||||||
|
*
|
||||||
|
* @param task the task to process.
|
||||||
|
* @param recurse the recursion count.
|
||||||
|
*/
|
||||||
|
var runNext = function(task, recurse) {
|
||||||
|
// get time since last context swap (ms), if enough time has passed set
|
||||||
|
// swap to true to indicate that doNext was performed asynchronously
|
||||||
|
// also, if recurse is too high do asynchronously
|
||||||
|
var swap =
|
||||||
|
(recurse > sMaxRecursions) ||
|
||||||
|
(+new Date() - task.swapTime) > sTimeSlice;
|
||||||
|
|
||||||
|
var doNext = function(recurse) {
|
||||||
|
recurse++;
|
||||||
|
if(task.state === RUNNING) {
|
||||||
|
if(swap) {
|
||||||
|
// update swap time
|
||||||
|
task.swapTime = +new Date();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(task.subtasks.length > 0) {
|
||||||
|
// run next subtask
|
||||||
|
var subtask = task.subtasks.shift();
|
||||||
|
subtask.error = task.error;
|
||||||
|
subtask.swapTime = task.swapTime;
|
||||||
|
subtask.userData = task.userData;
|
||||||
|
subtask.run(subtask);
|
||||||
|
if(!subtask.error) {
|
||||||
|
runNext(subtask, recurse);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
finish(task);
|
||||||
|
|
||||||
|
if(!task.error) {
|
||||||
|
// chain back up and run parent
|
||||||
|
if(task.parent !== null) {
|
||||||
|
// propagate task info
|
||||||
|
task.parent.error = task.error;
|
||||||
|
task.parent.swapTime = task.swapTime;
|
||||||
|
task.parent.userData = task.userData;
|
||||||
|
|
||||||
|
// no subtasks left, call run next subtask on parent
|
||||||
|
runNext(task.parent, recurse);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if(swap) {
|
||||||
|
// we're swapping, so run asynchronously
|
||||||
|
setTimeout(doNext, 0);
|
||||||
|
} else {
|
||||||
|
// not swapping, so run synchronously
|
||||||
|
doNext(recurse);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finishes a task and looks for the next task in the queue to start.
|
||||||
|
*
|
||||||
|
* @param task the task to finish.
|
||||||
|
* @param suppressCallbacks true to suppress callbacks.
|
||||||
|
*/
|
||||||
|
var finish = function(task, suppressCallbacks) {
|
||||||
|
// subtask is now done
|
||||||
|
task.state = DONE;
|
||||||
|
|
||||||
|
delete sTasks[task.id];
|
||||||
|
if(sVL >= 1) {
|
||||||
|
forge.log.verbose(cat, '[%s][%s] finish',
|
||||||
|
task.id, task.name, task);
|
||||||
|
}
|
||||||
|
|
||||||
|
// only do queue processing for root tasks
|
||||||
|
if(task.parent === null) {
|
||||||
|
// report error if queue is missing
|
||||||
|
if(!(task.type in sTaskQueues)) {
|
||||||
|
forge.log.error(cat,
|
||||||
|
'[%s][%s] task queue missing [%s]',
|
||||||
|
task.id, task.name, task.type);
|
||||||
|
} else if(sTaskQueues[task.type].length === 0) {
|
||||||
|
// report error if queue is empty
|
||||||
|
forge.log.error(cat,
|
||||||
|
'[%s][%s] task queue empty [%s]',
|
||||||
|
task.id, task.name, task.type);
|
||||||
|
} else if(sTaskQueues[task.type][0] !== task) {
|
||||||
|
// report error if this task isn't the first in the queue
|
||||||
|
forge.log.error(cat,
|
||||||
|
'[%s][%s] task not first in queue [%s]',
|
||||||
|
task.id, task.name, task.type);
|
||||||
|
} else {
|
||||||
|
// remove ourselves from the queue
|
||||||
|
sTaskQueues[task.type].shift();
|
||||||
|
// clean up queue if it is empty
|
||||||
|
if(sTaskQueues[task.type].length === 0) {
|
||||||
|
if(sVL >= 1) {
|
||||||
|
forge.log.verbose(cat, '[%s][%s] delete queue [%s]',
|
||||||
|
task.id, task.name, task.type);
|
||||||
|
}
|
||||||
|
/* Note: Only a task can delete a queue of its own type. This
|
||||||
|
is used as a way to synchronize tasks. If a queue for a certain
|
||||||
|
task type exists, then a task of that type is running.
|
||||||
|
*/
|
||||||
|
delete sTaskQueues[task.type];
|
||||||
|
} else {
|
||||||
|
// dequeue the next task and start it
|
||||||
|
if(sVL >= 1) {
|
||||||
|
forge.log.verbose(cat,
|
||||||
|
'[%s][%s] queue start next [%s] remain:%s',
|
||||||
|
task.id, task.name, task.type,
|
||||||
|
sTaskQueues[task.type].length);
|
||||||
|
}
|
||||||
|
sTaskQueues[task.type][0].start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!suppressCallbacks) {
|
||||||
|
// call final callback if one exists
|
||||||
|
if(task.error && task.failureCallback) {
|
||||||
|
task.failureCallback(task);
|
||||||
|
} else if(!task.error && task.successCallback) {
|
||||||
|
task.successCallback(task);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Tasks API */
|
||||||
|
forge.task = forge.task || {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts a new task that will run the passed function asynchronously.
|
||||||
|
*
|
||||||
|
* In order to finish the task, either task.doNext() or task.fail()
|
||||||
|
* *must* be called.
|
||||||
|
*
|
||||||
|
* The task must have a type (a string identifier) that can be used to
|
||||||
|
* synchronize it with other tasks of the same type. That type can also
|
||||||
|
* be used to cancel tasks that haven't started yet.
|
||||||
|
*
|
||||||
|
* To start a task, the following object must be provided as a parameter
|
||||||
|
* (each function takes a task object as its first parameter):
|
||||||
|
*
|
||||||
|
* {
|
||||||
|
* type: the type of task.
|
||||||
|
* run: the function to run to execute the task.
|
||||||
|
* success: a callback to call when the task succeeds (optional).
|
||||||
|
* failure: a callback to call when the task fails (optional).
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* @param options the object as described above.
|
||||||
|
*/
|
||||||
|
forge.task.start = function(options) {
|
||||||
|
// create a new task
|
||||||
|
var task = new Task({
|
||||||
|
run: options.run,
|
||||||
|
name: options.name || sNoTaskName
|
||||||
|
});
|
||||||
|
task.type = options.type;
|
||||||
|
task.successCallback = options.success || null;
|
||||||
|
task.failureCallback = options.failure || null;
|
||||||
|
|
||||||
|
// append the task onto the appropriate queue
|
||||||
|
if(!(task.type in sTaskQueues)) {
|
||||||
|
if(sVL >= 1) {
|
||||||
|
forge.log.verbose(cat, '[%s][%s] create queue [%s]',
|
||||||
|
task.id, task.name, task.type);
|
||||||
|
}
|
||||||
|
// create the queue with the new task
|
||||||
|
sTaskQueues[task.type] = [task];
|
||||||
|
start(task);
|
||||||
|
} else {
|
||||||
|
// push the task onto the queue, it will be run after a task
|
||||||
|
// with the same type completes
|
||||||
|
sTaskQueues[options.type].push(task);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancels all tasks of the given type that haven't started yet.
|
||||||
|
*
|
||||||
|
* @param type the type of task to cancel.
|
||||||
|
*/
|
||||||
|
forge.task.cancel = function(type) {
|
||||||
|
// find the task queue
|
||||||
|
if(type in sTaskQueues) {
|
||||||
|
// empty all but the current task from the queue
|
||||||
|
sTaskQueues[type] = [sTaskQueues[type][0]];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a condition variable to synchronize tasks. To make a task wait
|
||||||
|
* on the condition variable, call task.wait(condition). To notify all
|
||||||
|
* tasks that are waiting, call condition.notify().
|
||||||
|
*
|
||||||
|
* @return the condition variable.
|
||||||
|
*/
|
||||||
|
forge.task.createCondition = function() {
|
||||||
|
var cond = {
|
||||||
|
// all tasks that are blocked
|
||||||
|
tasks: {}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Causes the given task to block until notify is called. If the task
|
||||||
|
* is already waiting on this condition then this is a no-op.
|
||||||
|
*
|
||||||
|
* @param task the task to cause to wait.
|
||||||
|
*/
|
||||||
|
cond.wait = function(task) {
|
||||||
|
// only block once
|
||||||
|
if(!(task.id in cond.tasks)) {
|
||||||
|
task.block();
|
||||||
|
cond.tasks[task.id] = task;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notifies all waiting tasks to wake up.
|
||||||
|
*/
|
||||||
|
cond.notify = function() {
|
||||||
|
// since unblock() will run the next task from here, make sure to
|
||||||
|
// clear the condition's blocked task list before unblocking
|
||||||
|
var tmp = cond.tasks;
|
||||||
|
cond.tasks = {};
|
||||||
|
for(var id in tmp) {
|
||||||
|
tmp[id].unblock();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return cond;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // end module implementation
|
||||||
|
|
||||||
|
/* ########## Begin module wrapper ########## */
|
||||||
|
var name = 'task';
|
||||||
|
if(typeof define !== 'function') {
|
||||||
|
// NodeJS -> AMD
|
||||||
|
if(typeof module === 'object' && module.exports) {
|
||||||
|
var nodeJS = true;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
factory(require, module);
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
// <script>
|
||||||
|
if(typeof forge === 'undefined') {
|
||||||
|
forge = {};
|
||||||
|
}
|
||||||
|
return initModule(forge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// AMD
|
||||||
|
var deps;
|
||||||
|
var defineFunc = function(require, module) {
|
||||||
|
module.exports = function(forge) {
|
||||||
|
var mods = deps.map(function(dep) {
|
||||||
|
return require(dep);
|
||||||
|
}).concat(initModule);
|
||||||
|
// handle circular dependencies
|
||||||
|
forge = forge || {};
|
||||||
|
forge.defined = forge.defined || {};
|
||||||
|
if(forge.defined[name]) {
|
||||||
|
return forge[name];
|
||||||
|
}
|
||||||
|
forge.defined[name] = true;
|
||||||
|
for(var i = 0; i < mods.length; ++i) {
|
||||||
|
mods[i](forge);
|
||||||
|
}
|
||||||
|
return forge[name];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
var tmpDefine = define;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
|
||||||
|
if(nodeJS) {
|
||||||
|
delete define;
|
||||||
|
return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
}
|
||||||
|
define = tmpDefine;
|
||||||
|
return define.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
};
|
||||||
|
define(['require', 'module', './debug', './log', './util'], function() {
|
||||||
|
defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
});
|
||||||
|
})();
|
||||||
4316
forge.js/tls.js
Normal file
304
forge.js/tlssocket.js
Normal file
@@ -0,0 +1,304 @@
|
|||||||
|
/**
|
||||||
|
* Socket wrapping functions for TLS.
|
||||||
|
*
|
||||||
|
* @author Dave Longley
|
||||||
|
*
|
||||||
|
* Copyright (c) 2009-2012 Digital Bazaar, Inc.
|
||||||
|
*/
|
||||||
|
(function() {
|
||||||
|
/* ########## Begin module implementation ########## */
|
||||||
|
function initModule(forge) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wraps a forge.net socket with a TLS layer.
|
||||||
|
*
|
||||||
|
* @param options:
|
||||||
|
* sessionId: a session ID to reuse, null for a new connection if no session
|
||||||
|
* cache is provided or it is empty.
|
||||||
|
* caStore: an array of certificates to trust.
|
||||||
|
* sessionCache: a session cache to use.
|
||||||
|
* cipherSuites: an optional array of cipher suites to use, see
|
||||||
|
* tls.CipherSuites.
|
||||||
|
* socket: the socket to wrap.
|
||||||
|
* virtualHost: the virtual server name to use in a TLS SNI extension.
|
||||||
|
* verify: a handler used to custom verify certificates in the chain.
|
||||||
|
* getCertificate: an optional callback used to get a certificate.
|
||||||
|
* getPrivateKey: an optional callback used to get a private key.
|
||||||
|
* getSignature: an optional callback used to get a signature.
|
||||||
|
* deflate: function(inBytes) if provided, will deflate TLS records using
|
||||||
|
* the deflate algorithm if the server supports it.
|
||||||
|
* inflate: function(inBytes) if provided, will inflate TLS records using
|
||||||
|
* the deflate algorithm if the server supports it.
|
||||||
|
*
|
||||||
|
* @return the TLS-wrapped socket.
|
||||||
|
*/
|
||||||
|
forge.tls.wrapSocket = function(options) {
|
||||||
|
// get raw socket
|
||||||
|
var socket = options.socket;
|
||||||
|
|
||||||
|
// create TLS socket
|
||||||
|
var tlsSocket = {
|
||||||
|
id: socket.id,
|
||||||
|
// set handlers
|
||||||
|
connected: socket.connected || function(e){},
|
||||||
|
closed: socket.closed || function(e){},
|
||||||
|
data: socket.data || function(e){},
|
||||||
|
error: socket.error || function(e){}
|
||||||
|
};
|
||||||
|
|
||||||
|
// create TLS connection
|
||||||
|
var c = forge.tls.createConnection({
|
||||||
|
server: false,
|
||||||
|
sessionId: options.sessionId || null,
|
||||||
|
caStore: options.caStore || [],
|
||||||
|
sessionCache: options.sessionCache || null,
|
||||||
|
cipherSuites: options.cipherSuites || null,
|
||||||
|
virtualHost: options.virtualHost,
|
||||||
|
verify: options.verify,
|
||||||
|
getCertificate: options.getCertificate,
|
||||||
|
getPrivateKey: options.getPrivateKey,
|
||||||
|
getSignature: options.getSignature,
|
||||||
|
deflate: options.deflate,
|
||||||
|
inflate: options.inflate,
|
||||||
|
connected: function(c) {
|
||||||
|
// first handshake complete, call handler
|
||||||
|
if(c.handshakes === 1) {
|
||||||
|
tlsSocket.connected({
|
||||||
|
id: socket.id,
|
||||||
|
type: 'connect',
|
||||||
|
bytesAvailable: c.data.length()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
tlsDataReady: function(c) {
|
||||||
|
// send TLS data over socket
|
||||||
|
return socket.send(c.tlsData.getBytes());
|
||||||
|
},
|
||||||
|
dataReady: function(c) {
|
||||||
|
// indicate application data is ready
|
||||||
|
tlsSocket.data({
|
||||||
|
id: socket.id,
|
||||||
|
type: 'socketData',
|
||||||
|
bytesAvailable: c.data.length()
|
||||||
|
});
|
||||||
|
},
|
||||||
|
closed: function(c) {
|
||||||
|
// close socket
|
||||||
|
socket.close();
|
||||||
|
},
|
||||||
|
error: function(c, e) {
|
||||||
|
// send error, close socket
|
||||||
|
tlsSocket.error({
|
||||||
|
id: socket.id,
|
||||||
|
type: 'tlsError',
|
||||||
|
message: e.message,
|
||||||
|
bytesAvailable: 0,
|
||||||
|
error: e
|
||||||
|
});
|
||||||
|
socket.close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// handle doing handshake after connecting
|
||||||
|
socket.connected = function(e) {
|
||||||
|
c.handshake(options.sessionId);
|
||||||
|
};
|
||||||
|
|
||||||
|
// handle closing TLS connection
|
||||||
|
socket.closed = function(e) {
|
||||||
|
if(c.open && c.handshaking) {
|
||||||
|
// error
|
||||||
|
tlsSocket.error({
|
||||||
|
id: socket.id,
|
||||||
|
type: 'ioError',
|
||||||
|
message: 'Connection closed during handshake.',
|
||||||
|
bytesAvailable: 0
|
||||||
|
});
|
||||||
|
}
|
||||||
|
c.close();
|
||||||
|
|
||||||
|
// call socket handler
|
||||||
|
tlsSocket.closed({
|
||||||
|
id: socket.id,
|
||||||
|
type: 'close',
|
||||||
|
bytesAvailable: 0
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// handle error on socket
|
||||||
|
socket.error = function(e) {
|
||||||
|
// error
|
||||||
|
tlsSocket.error({
|
||||||
|
id: socket.id,
|
||||||
|
type: e.type,
|
||||||
|
message: e.message,
|
||||||
|
bytesAvailable: 0
|
||||||
|
});
|
||||||
|
c.close();
|
||||||
|
};
|
||||||
|
|
||||||
|
// handle receiving raw TLS data from socket
|
||||||
|
var _requiredBytes = 0;
|
||||||
|
socket.data = function(e) {
|
||||||
|
// drop data if connection not open
|
||||||
|
if(!c.open) {
|
||||||
|
socket.receive(e.bytesAvailable);
|
||||||
|
} else {
|
||||||
|
// only receive if there are enough bytes available to
|
||||||
|
// process a record
|
||||||
|
if(e.bytesAvailable >= _requiredBytes) {
|
||||||
|
var count = Math.max(e.bytesAvailable, _requiredBytes);
|
||||||
|
var data = socket.receive(count);
|
||||||
|
if(data !== null) {
|
||||||
|
_requiredBytes = c.process(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroys this socket.
|
||||||
|
*/
|
||||||
|
tlsSocket.destroy = function() {
|
||||||
|
socket.destroy();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets this socket's TLS session cache. This should be called before
|
||||||
|
* the socket is connected or after it is closed.
|
||||||
|
*
|
||||||
|
* The cache is an object mapping session IDs to internal opaque state.
|
||||||
|
* An application might need to change the cache used by a particular
|
||||||
|
* tlsSocket between connections if it accesses multiple TLS hosts.
|
||||||
|
*
|
||||||
|
* @param cache the session cache to use.
|
||||||
|
*/
|
||||||
|
tlsSocket.setSessionCache = function(cache) {
|
||||||
|
c.sessionCache = tls.createSessionCache(cache);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Connects this socket.
|
||||||
|
*
|
||||||
|
* @param options:
|
||||||
|
* host: the host to connect to.
|
||||||
|
* port: the port to connect to.
|
||||||
|
* policyPort: the policy port to use (if non-default), 0 to
|
||||||
|
* use the flash default.
|
||||||
|
* policyUrl: the policy file URL to use (instead of port).
|
||||||
|
*/
|
||||||
|
tlsSocket.connect = function(options) {
|
||||||
|
socket.connect(options);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Closes this socket.
|
||||||
|
*/
|
||||||
|
tlsSocket.close = function() {
|
||||||
|
c.close();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if the socket is connected or not.
|
||||||
|
*
|
||||||
|
* @return true if connected, false if not.
|
||||||
|
*/
|
||||||
|
tlsSocket.isConnected = function() {
|
||||||
|
return c.isConnected && socket.isConnected();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes bytes to this socket.
|
||||||
|
*
|
||||||
|
* @param bytes the bytes (as a string) to write.
|
||||||
|
*
|
||||||
|
* @return true on success, false on failure.
|
||||||
|
*/
|
||||||
|
tlsSocket.send = function(bytes) {
|
||||||
|
return c.prepare(bytes);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads bytes from this socket (non-blocking). Fewer than the number of
|
||||||
|
* bytes requested may be read if enough bytes are not available.
|
||||||
|
*
|
||||||
|
* This method should be called from the data handler if there are enough
|
||||||
|
* bytes available. To see how many bytes are available, check the
|
||||||
|
* 'bytesAvailable' property on the event in the data handler or call the
|
||||||
|
* bytesAvailable() function on the socket. If the browser is msie, then the
|
||||||
|
* bytesAvailable() function should be used to avoid race conditions.
|
||||||
|
* Otherwise, using the property on the data handler's event may be quicker.
|
||||||
|
*
|
||||||
|
* @param count the maximum number of bytes to read.
|
||||||
|
*
|
||||||
|
* @return the bytes read (as a string) or null on error.
|
||||||
|
*/
|
||||||
|
tlsSocket.receive = function(count) {
|
||||||
|
return c.data.getBytes(count);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the number of bytes available for receiving on the socket.
|
||||||
|
*
|
||||||
|
* @return the number of bytes available for receiving.
|
||||||
|
*/
|
||||||
|
tlsSocket.bytesAvailable = function() {
|
||||||
|
return c.data.length();
|
||||||
|
};
|
||||||
|
|
||||||
|
return tlsSocket;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // end module implementation
|
||||||
|
|
||||||
|
/* ########## Begin module wrapper ########## */
|
||||||
|
var name = 'tlssocket';
|
||||||
|
if(typeof define !== 'function') {
|
||||||
|
// NodeJS -> AMD
|
||||||
|
if(typeof module === 'object' && module.exports) {
|
||||||
|
var nodeJS = true;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
factory(require, module);
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
// <script>
|
||||||
|
if(typeof forge === 'undefined') {
|
||||||
|
forge = {};
|
||||||
|
}
|
||||||
|
return initModule(forge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// AMD
|
||||||
|
var deps;
|
||||||
|
var defineFunc = function(require, module) {
|
||||||
|
module.exports = function(forge) {
|
||||||
|
var mods = deps.map(function(dep) {
|
||||||
|
return require(dep);
|
||||||
|
}).concat(initModule);
|
||||||
|
// handle circular dependencies
|
||||||
|
forge = forge || {};
|
||||||
|
forge.defined = forge.defined || {};
|
||||||
|
if(forge.defined[name]) {
|
||||||
|
return forge[name];
|
||||||
|
}
|
||||||
|
forge.defined[name] = true;
|
||||||
|
for(var i = 0; i < mods.length; ++i) {
|
||||||
|
mods[i](forge);
|
||||||
|
}
|
||||||
|
return forge[name];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
var tmpDefine = define;
|
||||||
|
define = function(ids, factory) {
|
||||||
|
deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
|
||||||
|
if(nodeJS) {
|
||||||
|
delete define;
|
||||||
|
return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
}
|
||||||
|
define = tmpDefine;
|
||||||
|
return define.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
};
|
||||||
|
define(['require', 'module', './tls'], function() {
|
||||||
|
defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
|
||||||
|
});
|
||||||
|
})();
|
||||||
2988
forge.js/util.js
Normal file
3191
forge.js/x509.js
Normal file
739
forge.js/xhr.js
Normal file
@@ -0,0 +1,739 @@
|
|||||||
|
/**
|
||||||
|
* XmlHttpRequest implementation that uses TLS and flash SocketPool.
|
||||||
|
*
|
||||||
|
* @author Dave Longley
|
||||||
|
*
|
||||||
|
* Copyright (c) 2010-2013 Digital Bazaar, Inc.
|
||||||
|
*/
|
||||||
|
(function($) {
|
||||||
|
|
||||||
|
// logging category
|
||||||
|
var cat = 'forge.xhr';
|
||||||
|
|
||||||
|
/*
|
||||||
|
XMLHttpRequest interface definition from:
|
||||||
|
http://www.w3.org/TR/XMLHttpRequest
|
||||||
|
|
||||||
|
interface XMLHttpRequest {
|
||||||
|
// event handler
|
||||||
|
attribute EventListener onreadystatechange;
|
||||||
|
|
||||||
|
// state
|
||||||
|
const unsigned short UNSENT = 0;
|
||||||
|
const unsigned short OPENED = 1;
|
||||||
|
const unsigned short HEADERS_RECEIVED = 2;
|
||||||
|
const unsigned short LOADING = 3;
|
||||||
|
const unsigned short DONE = 4;
|
||||||
|
readonly attribute unsigned short readyState;
|
||||||
|
|
||||||
|
// request
|
||||||
|
void open(in DOMString method, in DOMString url);
|
||||||
|
void open(in DOMString method, in DOMString url, in boolean async);
|
||||||
|
void open(in DOMString method, in DOMString url,
|
||||||
|
in boolean async, in DOMString user);
|
||||||
|
void open(in DOMString method, in DOMString url,
|
||||||
|
in boolean async, in DOMString user, in DOMString password);
|
||||||
|
void setRequestHeader(in DOMString header, in DOMString value);
|
||||||
|
void send();
|
||||||
|
void send(in DOMString data);
|
||||||
|
void send(in Document data);
|
||||||
|
void abort();
|
||||||
|
|
||||||
|
// response
|
||||||
|
DOMString getAllResponseHeaders();
|
||||||
|
DOMString getResponseHeader(in DOMString header);
|
||||||
|
readonly attribute DOMString responseText;
|
||||||
|
readonly attribute Document responseXML;
|
||||||
|
readonly attribute unsigned short status;
|
||||||
|
readonly attribute DOMString statusText;
|
||||||
|
};
|
||||||
|
*/
|
||||||
|
|
||||||
|
// readyStates
|
||||||
|
var UNSENT = 0;
|
||||||
|
var OPENED = 1;
|
||||||
|
var HEADERS_RECEIVED = 2;
|
||||||
|
var LOADING = 3;
|
||||||
|
var DONE = 4;
|
||||||
|
|
||||||
|
// exceptions
|
||||||
|
var INVALID_STATE_ERR = 11;
|
||||||
|
var SYNTAX_ERR = 12;
|
||||||
|
var SECURITY_ERR = 18;
|
||||||
|
var NETWORK_ERR = 19;
|
||||||
|
var ABORT_ERR = 20;
|
||||||
|
|
||||||
|
// private flash socket pool vars
|
||||||
|
var _sp = null;
|
||||||
|
var _policyPort = 0;
|
||||||
|
var _policyUrl = null;
|
||||||
|
|
||||||
|
// default client (used if no special URL provided when creating an XHR)
|
||||||
|
var _client = null;
|
||||||
|
|
||||||
|
// all clients including the default, key'd by full base url
|
||||||
|
// (multiple cross-domain http clients are permitted so there may be more
|
||||||
|
// than one client in this map)
|
||||||
|
// TODO: provide optional clean up API for non-default clients
|
||||||
|
var _clients = {};
|
||||||
|
|
||||||
|
// the default maximum number of concurrents connections per client
|
||||||
|
var _maxConnections = 10;
|
||||||
|
|
||||||
|
// local aliases
|
||||||
|
if(typeof forge === 'undefined') {
|
||||||
|
forge = {};
|
||||||
|
}
|
||||||
|
var net = forge.net;
|
||||||
|
var http = forge.http;
|
||||||
|
|
||||||
|
// define the xhr interface
|
||||||
|
var xhrApi = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes flash XHR support.
|
||||||
|
*
|
||||||
|
* @param options:
|
||||||
|
* url: the default base URL to connect to if xhr URLs are relative,
|
||||||
|
* ie: https://myserver.com.
|
||||||
|
* flashId: the dom ID of the flash SocketPool.
|
||||||
|
* policyPort: the port that provides the server's flash policy, 0 to use
|
||||||
|
* the flash default.
|
||||||
|
* policyUrl: the policy file URL to use instead of a policy port.
|
||||||
|
* msie: true if browser is internet explorer, false if not.
|
||||||
|
* connections: the maximum number of concurrent connections.
|
||||||
|
* caCerts: a list of PEM-formatted certificates to trust.
|
||||||
|
* cipherSuites: an optional array of cipher suites to use,
|
||||||
|
* see forge.tls.CipherSuites.
|
||||||
|
* verify: optional TLS certificate verify callback to use (see forge.tls
|
||||||
|
* for details).
|
||||||
|
* getCertificate: an optional callback used to get a client-side
|
||||||
|
* certificate (see forge.tls for details).
|
||||||
|
* getPrivateKey: an optional callback used to get a client-side private
|
||||||
|
* key (see forge.tls for details).
|
||||||
|
* getSignature: an optional callback used to get a client-side signature
|
||||||
|
* (see forge.tls for details).
|
||||||
|
* persistCookies: true to use persistent cookies via flash local storage,
|
||||||
|
* false to only keep cookies in javascript.
|
||||||
|
* primeTlsSockets: true to immediately connect TLS sockets on their
|
||||||
|
* creation so that they will cache TLS sessions for reuse.
|
||||||
|
*/
|
||||||
|
xhrApi.init = function(options) {
|
||||||
|
forge.log.debug(cat, 'initializing', options);
|
||||||
|
|
||||||
|
// update default policy port and max connections
|
||||||
|
_policyPort = options.policyPort || _policyPort;
|
||||||
|
_policyUrl = options.policyUrl || _policyUrl;
|
||||||
|
_maxConnections = options.connections || _maxConnections;
|
||||||
|
|
||||||
|
// create the flash socket pool
|
||||||
|
_sp = net.createSocketPool({
|
||||||
|
flashId: options.flashId,
|
||||||
|
policyPort: _policyPort,
|
||||||
|
policyUrl: _policyUrl,
|
||||||
|
msie: options.msie || false
|
||||||
|
});
|
||||||
|
|
||||||
|
// create default http client
|
||||||
|
_client = http.createClient({
|
||||||
|
url: options.url || (
|
||||||
|
window.location.protocol + '//' + window.location.host),
|
||||||
|
socketPool: _sp,
|
||||||
|
policyPort: _policyPort,
|
||||||
|
policyUrl: _policyUrl,
|
||||||
|
connections: options.connections || _maxConnections,
|
||||||
|
caCerts: options.caCerts,
|
||||||
|
cipherSuites: options.cipherSuites,
|
||||||
|
persistCookies: options.persistCookies || true,
|
||||||
|
primeTlsSockets: options.primeTlsSockets || false,
|
||||||
|
verify: options.verify,
|
||||||
|
getCertificate: options.getCertificate,
|
||||||
|
getPrivateKey: options.getPrivateKey,
|
||||||
|
getSignature: options.getSignature
|
||||||
|
});
|
||||||
|
_clients[_client.url.full] = _client;
|
||||||
|
|
||||||
|
forge.log.debug(cat, 'ready');
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called to clean up the clients and socket pool.
|
||||||
|
*/
|
||||||
|
xhrApi.cleanup = function() {
|
||||||
|
// destroy all clients
|
||||||
|
for(var key in _clients) {
|
||||||
|
_clients[key].destroy();
|
||||||
|
}
|
||||||
|
_clients = {};
|
||||||
|
_client = null;
|
||||||
|
|
||||||
|
// destroy socket pool
|
||||||
|
_sp.destroy();
|
||||||
|
_sp = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a cookie.
|
||||||
|
*
|
||||||
|
* @param cookie the cookie with parameters:
|
||||||
|
* name: the name of the cookie.
|
||||||
|
* value: the value of the cookie.
|
||||||
|
* comment: an optional comment string.
|
||||||
|
* maxAge: the age of the cookie in seconds relative to created time.
|
||||||
|
* secure: true if the cookie must be sent over a secure protocol.
|
||||||
|
* httpOnly: true to restrict access to the cookie from javascript
|
||||||
|
* (inaffective since the cookies are stored in javascript).
|
||||||
|
* path: the path for the cookie.
|
||||||
|
* domain: optional domain the cookie belongs to (must start with dot).
|
||||||
|
* version: optional version of the cookie.
|
||||||
|
* created: creation time, in UTC seconds, of the cookie.
|
||||||
|
*/
|
||||||
|
xhrApi.setCookie = function(cookie) {
|
||||||
|
// default cookie expiration to never
|
||||||
|
cookie.maxAge = cookie.maxAge || -1;
|
||||||
|
|
||||||
|
// if the cookie's domain is set, use the appropriate client
|
||||||
|
if(cookie.domain) {
|
||||||
|
// add the cookies to the applicable domains
|
||||||
|
for(var key in _clients) {
|
||||||
|
var client = _clients[key];
|
||||||
|
if(http.withinCookieDomain(client.url, cookie) &&
|
||||||
|
client.secure === cookie.secure) {
|
||||||
|
client.setCookie(cookie);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// use the default domain
|
||||||
|
// FIXME: should a null domain cookie be added to all clients? should
|
||||||
|
// this be an option?
|
||||||
|
_client.setCookie(cookie);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a cookie.
|
||||||
|
*
|
||||||
|
* @param name the name of the cookie.
|
||||||
|
* @param path an optional path for the cookie (if there are multiple cookies
|
||||||
|
* with the same name but different paths).
|
||||||
|
* @param domain an optional domain for the cookie (if not using the default
|
||||||
|
* domain).
|
||||||
|
*
|
||||||
|
* @return the cookie, cookies (if multiple matches), or null if not found.
|
||||||
|
*/
|
||||||
|
xhrApi.getCookie = function(name, path, domain) {
|
||||||
|
var rval = null;
|
||||||
|
|
||||||
|
if(domain) {
|
||||||
|
// get the cookies from the applicable domains
|
||||||
|
for(var key in _clients) {
|
||||||
|
var client = _clients[key];
|
||||||
|
if(http.withinCookieDomain(client.url, domain)) {
|
||||||
|
var cookie = client.getCookie(name, path);
|
||||||
|
if(cookie !== null) {
|
||||||
|
if(rval === null) {
|
||||||
|
rval = cookie;
|
||||||
|
} else if(!forge.util.isArray(rval)) {
|
||||||
|
rval = [rval, cookie];
|
||||||
|
} else {
|
||||||
|
rval.push(cookie);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// get cookie from default domain
|
||||||
|
rval = _client.getCookie(name, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rval;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a cookie.
|
||||||
|
*
|
||||||
|
* @param name the name of the cookie.
|
||||||
|
* @param path an optional path for the cookie (if there are multiple cookies
|
||||||
|
* with the same name but different paths).
|
||||||
|
* @param domain an optional domain for the cookie (if not using the default
|
||||||
|
* domain).
|
||||||
|
*
|
||||||
|
* @return true if a cookie was removed, false if not.
|
||||||
|
*/
|
||||||
|
xhrApi.removeCookie = function(name, path, domain) {
|
||||||
|
var rval = false;
|
||||||
|
|
||||||
|
if(domain) {
|
||||||
|
// remove the cookies from the applicable domains
|
||||||
|
for(var key in _clients) {
|
||||||
|
var client = _clients[key];
|
||||||
|
if(http.withinCookieDomain(client.url, domain)) {
|
||||||
|
if(client.removeCookie(name, path)) {
|
||||||
|
rval = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// remove cookie from default domain
|
||||||
|
rval = _client.removeCookie(name, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rval;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new XmlHttpRequest. By default the base URL, flash policy port,
|
||||||
|
* etc, will be used. However, an XHR can be created to point at another
|
||||||
|
* cross-domain URL.
|
||||||
|
*
|
||||||
|
* @param options:
|
||||||
|
* logWarningOnError: If true and an HTTP error status code is received then
|
||||||
|
* log a warning, otherwise log a verbose message.
|
||||||
|
* verbose: If true be very verbose in the output including the response
|
||||||
|
* event and response body, otherwise only include status, timing, and
|
||||||
|
* data size.
|
||||||
|
* logError: a multi-var log function for warnings that takes the log
|
||||||
|
* category as the first var.
|
||||||
|
* logWarning: a multi-var log function for warnings that takes the log
|
||||||
|
* category as the first var.
|
||||||
|
* logDebug: a multi-var log function for warnings that takes the log
|
||||||
|
* category as the first var.
|
||||||
|
* logVerbose: a multi-var log function for warnings that takes the log
|
||||||
|
* category as the first var.
|
||||||
|
* url: the default base URL to connect to if xhr URLs are relative,
|
||||||
|
* eg: https://myserver.com, and note that the following options will be
|
||||||
|
* ignored if the URL is absent or the same as the default base URL.
|
||||||
|
* policyPort: the port that provides the server's flash policy, 0 to use
|
||||||
|
* the flash default.
|
||||||
|
* policyUrl: the policy file URL to use instead of a policy port.
|
||||||
|
* connections: the maximum number of concurrent connections.
|
||||||
|
* caCerts: a list of PEM-formatted certificates to trust.
|
||||||
|
* cipherSuites: an optional array of cipher suites to use, see
|
||||||
|
* forge.tls.CipherSuites.
|
||||||
|
* verify: optional TLS certificate verify callback to use (see forge.tls
|
||||||
|
* for details).
|
||||||
|
* getCertificate: an optional callback used to get a client-side
|
||||||
|
* certificate.
|
||||||
|
* getPrivateKey: an optional callback used to get a client-side private key.
|
||||||
|
* getSignature: an optional callback used to get a client-side signature.
|
||||||
|
* persistCookies: true to use persistent cookies via flash local storage,
|
||||||
|
* false to only keep cookies in javascript.
|
||||||
|
* primeTlsSockets: true to immediately connect TLS sockets on their
|
||||||
|
* creation so that they will cache TLS sessions for reuse.
|
||||||
|
*
|
||||||
|
* @return the XmlHttpRequest.
|
||||||
|
*/
|
||||||
|
xhrApi.create = function(options) {
|
||||||
|
// set option defaults
|
||||||
|
options = $.extend({
|
||||||
|
logWarningOnError: true,
|
||||||
|
verbose: false,
|
||||||
|
logError: function(){},
|
||||||
|
logWarning: function(){},
|
||||||
|
logDebug: function(){},
|
||||||
|
logVerbose: function(){},
|
||||||
|
url: null
|
||||||
|
}, options || {});
|
||||||
|
|
||||||
|
// private xhr state
|
||||||
|
var _state = {
|
||||||
|
// the http client to use
|
||||||
|
client: null,
|
||||||
|
// request storage
|
||||||
|
request: null,
|
||||||
|
// response storage
|
||||||
|
response: null,
|
||||||
|
// asynchronous, true if doing asynchronous communication
|
||||||
|
asynchronous: true,
|
||||||
|
// sendFlag, true if send has been called
|
||||||
|
sendFlag: false,
|
||||||
|
// errorFlag, true if a network error occurred
|
||||||
|
errorFlag: false
|
||||||
|
};
|
||||||
|
|
||||||
|
// private log functions
|
||||||
|
var _log = {
|
||||||
|
error: options.logError || forge.log.error,
|
||||||
|
warning: options.logWarning || forge.log.warning,
|
||||||
|
debug: options.logDebug || forge.log.debug,
|
||||||
|
verbose: options.logVerbose || forge.log.verbose
|
||||||
|
};
|
||||||
|
|
||||||
|
// create public xhr interface
|
||||||
|
var xhr = {
|
||||||
|
// an EventListener
|
||||||
|
onreadystatechange: null,
|
||||||
|
// readonly, the current readyState
|
||||||
|
readyState: UNSENT,
|
||||||
|
// a string with the response entity-body
|
||||||
|
responseText: '',
|
||||||
|
// a Document for response entity-bodies that are XML
|
||||||
|
responseXML: null,
|
||||||
|
// readonly, returns the HTTP status code (i.e. 404)
|
||||||
|
status: 0,
|
||||||
|
// readonly, returns the HTTP status message (i.e. 'Not Found')
|
||||||
|
statusText: ''
|
||||||
|
};
|
||||||
|
|
||||||
|
// determine which http client to use
|
||||||
|
if(options.url === null) {
|
||||||
|
// use default
|
||||||
|
_state.client = _client;
|
||||||
|
} else {
|
||||||
|
var url = http.parseUrl(options.url);
|
||||||
|
if(!url) {
|
||||||
|
var error = new Error('Invalid url.');
|
||||||
|
error.details = {
|
||||||
|
url: options.url
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// find client
|
||||||
|
if(url.full in _clients) {
|
||||||
|
// client found
|
||||||
|
_state.client = _clients[url.full];
|
||||||
|
} else {
|
||||||
|
// create client
|
||||||
|
_state.client = http.createClient({
|
||||||
|
url: options.url,
|
||||||
|
socketPool: _sp,
|
||||||
|
policyPort: options.policyPort || _policyPort,
|
||||||
|
policyUrl: options.policyUrl || _policyUrl,
|
||||||
|
connections: options.connections || _maxConnections,
|
||||||
|
caCerts: options.caCerts,
|
||||||
|
cipherSuites: options.cipherSuites,
|
||||||
|
persistCookies: options.persistCookies || true,
|
||||||
|
primeTlsSockets: options.primeTlsSockets || false,
|
||||||
|
verify: options.verify,
|
||||||
|
getCertificate: options.getCertificate,
|
||||||
|
getPrivateKey: options.getPrivateKey,
|
||||||
|
getSignature: options.getSignature
|
||||||
|
});
|
||||||
|
_clients[url.full] = _state.client;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens the request. This method will create the HTTP request to send.
|
||||||
|
*
|
||||||
|
* @param method the HTTP method (i.e. 'GET').
|
||||||
|
* @param url the relative url (the HTTP request path).
|
||||||
|
* @param async always true, ignored.
|
||||||
|
* @param user always null, ignored.
|
||||||
|
* @param password always null, ignored.
|
||||||
|
*/
|
||||||
|
xhr.open = function(method, url, async, user, password) {
|
||||||
|
// 1. validate Document if one is associated
|
||||||
|
// TODO: not implemented (not used yet)
|
||||||
|
|
||||||
|
// 2. validate method token
|
||||||
|
// 3. change method to uppercase if it matches a known
|
||||||
|
// method (here we just require it to be uppercase, and
|
||||||
|
// we do not allow the standard methods)
|
||||||
|
// 4. disallow CONNECT, TRACE, or TRACK with a security error
|
||||||
|
switch(method) {
|
||||||
|
case 'DELETE':
|
||||||
|
case 'GET':
|
||||||
|
case 'HEAD':
|
||||||
|
case 'OPTIONS':
|
||||||
|
case 'PATCH':
|
||||||
|
case 'POST':
|
||||||
|
case 'PUT':
|
||||||
|
// valid method
|
||||||
|
break;
|
||||||
|
case 'CONNECT':
|
||||||
|
case 'TRACE':
|
||||||
|
case 'TRACK':
|
||||||
|
throw new Error('CONNECT, TRACE and TRACK methods are disallowed');
|
||||||
|
default:
|
||||||
|
throw new Error('Invalid method: ' + method);;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: other validation steps in algorithm are not implemented
|
||||||
|
|
||||||
|
// 19. set send flag to false
|
||||||
|
// set response body to null
|
||||||
|
// empty list of request headers
|
||||||
|
// set request method to given method
|
||||||
|
// set request URL
|
||||||
|
// set username, password
|
||||||
|
// set asychronous flag
|
||||||
|
_state.sendFlag = false;
|
||||||
|
xhr.responseText = '';
|
||||||
|
xhr.responseXML = null;
|
||||||
|
|
||||||
|
// custom: reset status and statusText
|
||||||
|
xhr.status = 0;
|
||||||
|
xhr.statusText = '';
|
||||||
|
|
||||||
|
// create the HTTP request
|
||||||
|
_state.request = http.createRequest({
|
||||||
|
method: method,
|
||||||
|
path: url
|
||||||
|
});
|
||||||
|
|
||||||
|
// 20. set state to OPENED
|
||||||
|
xhr.readyState = OPENED;
|
||||||
|
|
||||||
|
// 21. dispatch onreadystatechange
|
||||||
|
if(xhr.onreadystatechange) {
|
||||||
|
xhr.onreadystatechange();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an HTTP header field to the request.
|
||||||
|
*
|
||||||
|
* @param header the name of the header field.
|
||||||
|
* @param value the value of the header field.
|
||||||
|
*/
|
||||||
|
xhr.setRequestHeader = function(header, value) {
|
||||||
|
// 1. if state is not OPENED or send flag is true, raise exception
|
||||||
|
if(xhr.readyState != OPENED || _state.sendFlag) {
|
||||||
|
throw new Error('XHR not open or sending');
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: other validation steps in spec aren't implemented
|
||||||
|
|
||||||
|
// set header
|
||||||
|
_state.request.setField(header, value);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends the request and any associated data.
|
||||||
|
*
|
||||||
|
* @param data a string or Document object to send, null to send no data.
|
||||||
|
*/
|
||||||
|
xhr.send = function(data) {
|
||||||
|
// 1. if state is not OPENED or 2. send flag is true, raise
|
||||||
|
// an invalid state exception
|
||||||
|
if(xhr.readyState != OPENED || _state.sendFlag) {
|
||||||
|
throw new Error('XHR not open or sending');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. ignore data if method is GET or HEAD
|
||||||
|
if(data &&
|
||||||
|
_state.request.method !== 'GET' &&
|
||||||
|
_state.request.method !== 'HEAD') {
|
||||||
|
// handle non-IE case
|
||||||
|
if(typeof(XMLSerializer) !== 'undefined') {
|
||||||
|
if(data instanceof Document) {
|
||||||
|
var xs = new XMLSerializer();
|
||||||
|
_state.request.body = xs.serializeToString(data);
|
||||||
|
} else {
|
||||||
|
_state.request.body = data;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// poorly implemented IE case
|
||||||
|
if(typeof(data.xml) !== 'undefined') {
|
||||||
|
_state.request.body = data.xml;
|
||||||
|
} else {
|
||||||
|
_state.request.body = data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. release storage mutex (not used)
|
||||||
|
|
||||||
|
// 5. set error flag to false
|
||||||
|
_state.errorFlag = false;
|
||||||
|
|
||||||
|
// 6. if asynchronous is true (must be in this implementation)
|
||||||
|
|
||||||
|
// 6.1 set send flag to true
|
||||||
|
_state.sendFlag = true;
|
||||||
|
|
||||||
|
// 6.2 dispatch onreadystatechange
|
||||||
|
if(xhr.onreadystatechange) {
|
||||||
|
xhr.onreadystatechange();
|
||||||
|
}
|
||||||
|
|
||||||
|
// create send options
|
||||||
|
var options = {};
|
||||||
|
options.request = _state.request;
|
||||||
|
options.headerReady = function(e) {
|
||||||
|
// make cookies available for ease of use/iteration
|
||||||
|
xhr.cookies = _state.client.cookies;
|
||||||
|
|
||||||
|
// TODO: update document.cookie with any cookies where the
|
||||||
|
// script's domain matches
|
||||||
|
|
||||||
|
// headers received
|
||||||
|
xhr.readyState = HEADERS_RECEIVED;
|
||||||
|
xhr.status = e.response.code;
|
||||||
|
xhr.statusText = e.response.message;
|
||||||
|
_state.response = e.response;
|
||||||
|
if(xhr.onreadystatechange) {
|
||||||
|
xhr.onreadystatechange();
|
||||||
|
}
|
||||||
|
if(!_state.response.aborted) {
|
||||||
|
// now loading body
|
||||||
|
xhr.readyState = LOADING;
|
||||||
|
if(xhr.onreadystatechange) {
|
||||||
|
xhr.onreadystatechange();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
options.bodyReady = function(e) {
|
||||||
|
xhr.readyState = DONE;
|
||||||
|
var ct = e.response.getField('Content-Type');
|
||||||
|
// Note: this null/undefined check is done outside because IE
|
||||||
|
// dies otherwise on a "'null' is null" error
|
||||||
|
if(ct) {
|
||||||
|
if(ct.indexOf('text/xml') === 0 ||
|
||||||
|
ct.indexOf('application/xml') === 0 ||
|
||||||
|
ct.indexOf('+xml') !== -1) {
|
||||||
|
try {
|
||||||
|
var doc = new ActiveXObject('MicrosoftXMLDOM');
|
||||||
|
doc.async = false;
|
||||||
|
doc.loadXML(e.response.body);
|
||||||
|
xhr.responseXML = doc;
|
||||||
|
} catch(ex) {
|
||||||
|
var parser = new DOMParser();
|
||||||
|
xhr.responseXML = parser.parseFromString(ex.body, 'text/xml');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var length = 0;
|
||||||
|
if(e.response.body !== null) {
|
||||||
|
xhr.responseText = e.response.body;
|
||||||
|
length = e.response.body.length;
|
||||||
|
}
|
||||||
|
// build logging output
|
||||||
|
var req = _state.request;
|
||||||
|
var output =
|
||||||
|
req.method + ' ' + req.path + ' ' +
|
||||||
|
xhr.status + ' ' + xhr.statusText + ' ' +
|
||||||
|
length + 'B ' +
|
||||||
|
(e.request.connectTime + e.request.time + e.response.time) +
|
||||||
|
'ms';
|
||||||
|
var lFunc;
|
||||||
|
if(options.verbose) {
|
||||||
|
lFunc = (xhr.status >= 400 && options.logWarningOnError) ?
|
||||||
|
_log.warning : _log.verbose;
|
||||||
|
lFunc(cat, output,
|
||||||
|
e, e.response.body ? '\n' + e.response.body : '\nNo content');
|
||||||
|
} else {
|
||||||
|
lFunc = (xhr.status >= 400 && options.logWarningOnError) ?
|
||||||
|
_log.warning : _log.debug;
|
||||||
|
lFunc(cat, output);
|
||||||
|
}
|
||||||
|
if(xhr.onreadystatechange) {
|
||||||
|
xhr.onreadystatechange();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
options.error = function(e) {
|
||||||
|
var req = _state.request;
|
||||||
|
_log.error(cat, req.method + ' ' + req.path, e);
|
||||||
|
|
||||||
|
// 1. set response body to null
|
||||||
|
xhr.responseText = '';
|
||||||
|
xhr.responseXML = null;
|
||||||
|
|
||||||
|
// 2. set error flag to true (and reset status)
|
||||||
|
_state.errorFlag = true;
|
||||||
|
xhr.status = 0;
|
||||||
|
xhr.statusText = '';
|
||||||
|
|
||||||
|
// 3. set state to done
|
||||||
|
xhr.readyState = DONE;
|
||||||
|
|
||||||
|
// 4. asyc flag is always true, so dispatch onreadystatechange
|
||||||
|
if(xhr.onreadystatechange) {
|
||||||
|
xhr.onreadystatechange();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 7. send request
|
||||||
|
_state.client.send(options);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Aborts the request.
|
||||||
|
*/
|
||||||
|
xhr.abort = function() {
|
||||||
|
// 1. abort send
|
||||||
|
// 2. stop network activity
|
||||||
|
_state.request.abort();
|
||||||
|
|
||||||
|
// 3. set response to null
|
||||||
|
xhr.responseText = '';
|
||||||
|
xhr.responseXML = null;
|
||||||
|
|
||||||
|
// 4. set error flag to true (and reset status)
|
||||||
|
_state.errorFlag = true;
|
||||||
|
xhr.status = 0;
|
||||||
|
xhr.statusText = '';
|
||||||
|
|
||||||
|
// 5. clear user headers
|
||||||
|
_state.request = null;
|
||||||
|
_state.response = null;
|
||||||
|
|
||||||
|
// 6. if state is DONE or UNSENT, or if OPENED and send flag is false
|
||||||
|
if(xhr.readyState === DONE || xhr.readyState === UNSENT ||
|
||||||
|
(xhr.readyState === OPENED && !_state.sendFlag)) {
|
||||||
|
// 7. set ready state to unsent
|
||||||
|
xhr.readyState = UNSENT;
|
||||||
|
} else {
|
||||||
|
// 6.1 set state to DONE
|
||||||
|
xhr.readyState = DONE;
|
||||||
|
|
||||||
|
// 6.2 set send flag to false
|
||||||
|
_state.sendFlag = false;
|
||||||
|
|
||||||
|
// 6.3 dispatch onreadystatechange
|
||||||
|
if(xhr.onreadystatechange) {
|
||||||
|
xhr.onreadystatechange();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 7. set state to UNSENT
|
||||||
|
xhr.readyState = UNSENT;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets all response headers as a string.
|
||||||
|
*
|
||||||
|
* @return the HTTP-encoded response header fields.
|
||||||
|
*/
|
||||||
|
xhr.getAllResponseHeaders = function() {
|
||||||
|
var rval = '';
|
||||||
|
if(_state.response !== null) {
|
||||||
|
var fields = _state.response.fields;
|
||||||
|
$.each(fields, function(name, array) {
|
||||||
|
$.each(array, function(i, value) {
|
||||||
|
rval += name + ': ' + value + '\r\n';
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return rval;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a single header field value or, if there are multiple
|
||||||
|
* fields with the same name, a comma-separated list of header
|
||||||
|
* values.
|
||||||
|
*
|
||||||
|
* @return the header field value(s) or null.
|
||||||
|
*/
|
||||||
|
xhr.getResponseHeader = function(header) {
|
||||||
|
var rval = null;
|
||||||
|
if(_state.response !== null) {
|
||||||
|
if(header in _state.response.fields) {
|
||||||
|
rval = _state.response.fields[header];
|
||||||
|
if(forge.util.isArray(rval)) {
|
||||||
|
rval = rval.join();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rval;
|
||||||
|
};
|
||||||
|
|
||||||
|
return xhr;
|
||||||
|
};
|
||||||
|
|
||||||
|
// expose public api
|
||||||
|
forge.xhr = xhrApi;
|
||||||
|
|
||||||
|
})(jQuery);
|
||||||
BIN
images-commander/Thumbs.db
Normal file
BIN
images-commander/certificate-1.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
images-commander/error.gif
Normal file
|
After Width: | Height: | Size: 149 B |
BIN
images-commander/error.png
Normal file
|
After Width: | Height: | Size: 3.5 KiB |
BIN
images-commander/icons16.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
images-commander/icons200-1-1.png
Normal file
|
After Width: | Height: | Size: 30 KiB |
BIN
images-commander/icons200-2-1.png
Normal file
|
After Width: | Height: | Size: 37 KiB |
BIN
images-commander/icons200-3-1.png
Normal file
|
After Width: | Height: | Size: 35 KiB |
BIN
images-commander/icons200-4-1.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
images-commander/icons200-5-1.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
images-commander/icons200-6-1.png
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
images-commander/icons26.png
Normal file
|
After Width: | Height: | Size: 8.9 KiB |
BIN
images-commander/icons50.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
images-commander/info.gif
Normal file
|
After Width: | Height: | Size: 197 B |
BIN
images-commander/info.png
Normal file
|
After Width: | Height: | Size: 3.5 KiB |
BIN
images-commander/leftbar-32.png
Normal file
|
After Width: | Height: | Size: 4.8 KiB |
BIN
images-commander/leftbar-44.png
Normal file
|
After Width: | Height: | Size: 7.7 KiB |
BIN
images-commander/logo-old.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
images-commander/logo.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
images-commander/logoback.png
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
images-commander/logox.png
Normal file
|
After Width: | Height: | Size: 13 KiB |