Added Web based RDP support with NLA, #3867 and #3914

Ylian Saint-Hilaire committed Apr 29, 2022 at 11:13 UTC db06ec1975af17e0a5f72bfccacacb72d369dd21
37 files changed +28171 -41
MeshCentralServer.njsproj
+40
@@ -182,6 +182,37 @@
182 <Compile Include="public\novnc\vendor\promise.js" />
183 <Compile Include="public\scripts\agent-redir-rtc-0.1.0.js" />
184 <Compile Include="public\serviceworker.js" />
185 + <Compile Include="rdp\asn1\ber.js" />
186 + <Compile Include="rdp\asn1\index.js" />
187 + <Compile Include="rdp\asn1\spec.js" />
188 + <Compile Include="rdp\asn1\univ.js" />
189 + <Compile Include="rdp\core\error.js" />
190 + <Compile Include="rdp\core\index.js" />
191 + <Compile Include="rdp\core\layer.js" />
192 + <Compile Include="rdp\core\log.js" />
193 + <Compile Include="rdp\core\rle.js" />
194 + <Compile Include="rdp\core\type.js" />
195 + <Compile Include="rdp\index.js" />
196 + <Compile Include="rdp\protocol\cert.js" />
197 + <Compile Include="rdp\protocol\index.js" />
198 + <Compile Include="rdp\protocol\nla.js" />
199 + <Compile Include="rdp\protocol\pdu\caps.js" />
200 + <Compile Include="rdp\protocol\pdu\data.js" />
201 + <Compile Include="rdp\protocol\pdu\global.js" />
202 + <Compile Include="rdp\protocol\pdu\index.js" />
203 + <Compile Include="rdp\protocol\pdu\lic.js" />
204 + <Compile Include="rdp\protocol\pdu\sec.js" />
205 + <Compile Include="rdp\protocol\rdp.js" />
206 + <Compile Include="rdp\protocol\t125\gcc.js" />
207 + <Compile Include="rdp\protocol\t125\index.js" />
208 + <Compile Include="rdp\protocol\t125\mcs.js" />
209 + <Compile Include="rdp\protocol\t125\per.js" />
210 + <Compile Include="rdp\protocol\tpkt.js" />
211 + <Compile Include="rdp\protocol\x224.js" />
212 + <Compile Include="rdp\security\index.js" />
213 + <Compile Include="rdp\security\jsbn.js" />
214 + <Compile Include="rdp\security\rsa.js" />
215 + <Compile Include="rdp\security\x509.js" />
216 <Compile Include="swarmserver.js" />
217 <Compile Include="multiserver.js" />
218 <Compile Include="pass.js" />
@@ -550,6 +581,8 @@
581 <Content Include="public\styles\style.css" />
582 <Content Include="public\translate.bat" />
583 <Content Include="public\translator.htm" />
584 + <Content Include="rdp\LICENSE" />
585 + <Content Include="rdp\README.md" />
586 <Content Include="readme.md" />
587 <Content Include="sample-config-advanced.json" />
588 <Content Include="sample-config.json" />
@@ -624,6 +657,13 @@
657 <Folder Include="public\styles\font-awesome\fonts\" />
658 <Folder Include="public\styles\font-awesome\less\" />
659 <Folder Include="public\styles\font-awesome\scss\" />
660 + <Folder Include="rdp\" />
661 + <Folder Include="rdp\asn1\" />
662 + <Folder Include="rdp\core\" />
663 + <Folder Include="rdp\protocol\" />
664 + <Folder Include="rdp\protocol\pdu\" />
665 + <Folder Include="rdp\protocol\t125\" />
666 + <Folder Include="rdp\security\" />
667 <Folder Include="translate\" />
668 <Folder Include="typings\" />
669 <Folder Include="typings\globals\" />
apprelays.js
+3 -2
@@ -129,8 +129,9 @@ module.exports.CreateMstscRelay = function (parent, db, ws, req, args, domain) {
129 function startRdp(port) {
130 parent.parent.debug('relay', 'RDP: Starting RDP client on loopback port ' + port);
131 try {
132 - rdpClient = require('node-rdpjs-2').createClient({
133 - logLevel: 'ERROR',
132 + //rdpClient = require('node-rdpjs-2').createClient({
133 + rdpClient = require('./rdp').createClient({
134 + logLevel: 'NONE', // 'ERROR',
135 domain: obj.infos.domain,
136 userName: obj.infos.username,
137 password: obj.infos.password,
meshcentral.js
+5 -3
@@ -3478,13 +3478,16 @@ function mainStart() {
3478 const verSplit = process.version.substring(1).split('.');
3479 var nodeVersion = parseInt(verSplit[0]) + (parseInt(verSplit[1]) / 100);
3480
3481 + // Check if RDP support if present
3482 + var mstsc = true;
3483 + try { require('./rdp') } catch (ex) { mstsc = false; }
3484 +
3485 // Check if Windows SSPI, LDAP, Passport and YubiKey OTP will be used
3486 var sspi = false;
3487 var ldap = false;
3488 var passport = null;
3489 var allsspi = true;
3490 var yubikey = false;
3487 - var mstsc = false;
3491 var ssh = false;
3492 var sessionRecording = false;
3493 var domainCount = 0;
@@ -3499,7 +3502,7 @@ function mainStart() {
3502 if (config.domains[i].sendgrid != null) { sendgrid = true; }
3503 if (config.domains[i].yubikey != null) { yubikey = true; }
3504 if (config.domains[i].auth == 'ldap') { ldap = true; }
3502 - if (config.domains[i].mstsc == true) { mstsc = true; }
3505 + if (mstsc == false) { config.domains[i].mstsc = false; }
3506 if (config.domains[i].ssh == true) { if (nodeVersion < 11) { config.domains[i].ssh = false; } ssh = true; }
3507 if ((typeof config.domains[i].authstrategies == 'object')) {
3508 if (passport == null) { passport = ['passport']; }
@@ -3519,7 +3522,6 @@ function mainStart() {
3522 var modules = ['ws@5.2.3', 'cbor@5.2.0', '@yetzt/nedb', 'https', 'yauzl', 'ipcheck', 'express', 'archiver@4.0.2', 'multiparty', 'node-forge', 'express-ws@4.0.0', 'compression', 'body-parser', 'cookie-session@1.4.0', 'express-handlebars'];
3523 if (require('os').platform() == 'win32') { modules.push('node-windows@0.1.4'); modules.push('loadavg-windows'); if (sspi == true) { modules.push('node-sspi'); } } // Add Windows modules
3524 if (ldap == true) { modules.push('ldapauth-fork'); }
3522 - if (mstsc == true) { modules.push('node-rdpjs-2'); }
3525 if (ssh == true) { if (nodeVersion < 11) { addServerWarning('MeshCentral SSH support requires NodeJS 11 or higher.', 1); } else { modules.push('ssh2'); } }
3526 if (passport != null) { modules.push(...passport); }
3527 if (sessionRecording == true) { modules.push('image-size'); } // Need to get the remote desktop JPEG sizes to index the recodring file.
rdp/LICENSE new
+674
@@ -0,0 +1,674 @@
1 +GNU GENERAL PUBLIC LICENSE
2 + Version 3, 29 June 2007
3 +
4 + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
5 + Everyone is permitted to copy and distribute verbatim copies
6 + of this license document, but changing it is not allowed.
7 +
8 + Preamble
9 +
10 + The GNU General Public License is a free, copyleft license for
11 +software and other kinds of works.
12 +
13 + The licenses for most software and other practical works are designed
14 +to take away your freedom to share and change the works. By contrast,
15 +the GNU General Public License is intended to guarantee your freedom to
16 +share and change all versions of a program--to make sure it remains free
17 +software for all its users. We, the Free Software Foundation, use the
18 +GNU General Public License for most of our software; it applies also to
19 +any other work released this way by its authors. You can apply it to
20 +your programs, too.
21 +
22 + When we speak of free software, we are referring to freedom, not
23 +price. Our General Public Licenses are designed to make sure that you
24 +have the freedom to distribute copies of free software (and charge for
25 +them if you wish), that you receive source code or can get it if you
26 +want it, that you can change the software or use pieces of it in new
27 +free programs, and that you know you can do these things.
28 +
29 + To protect your rights, we need to prevent others from denying you
30 +these rights or asking you to surrender the rights. Therefore, you have
31 +certain responsibilities if you distribute copies of the software, or if
32 +you modify it: responsibilities to respect the freedom of others.
33 +
34 + For example, if you distribute copies of such a program, whether
35 +gratis or for a fee, you must pass on to the recipients the same
36 +freedoms that you received. You must make sure that they, too, receive
37 +or can get the source code. And you must show them these terms so they
38 +know their rights.
39 +
40 + Developers that use the GNU GPL protect your rights with two steps:
41 +(1) assert copyright on the software, and (2) offer you this License
42 +giving you legal permission to copy, distribute and/or modify it.
43 +
44 + For the developers' and authors' protection, the GPL clearly explains
45 +that there is no warranty for this free software. For both users' and
46 +authors' sake, the GPL requires that modified versions be marked as
47 +changed, so that their problems will not be attributed erroneously to
48 +authors of previous versions.
49 +
50 + Some devices are designed to deny users access to install or run
51 +modified versions of the software inside them, although the manufacturer
52 +can do so. This is fundamentally incompatible with the aim of
53 +protecting users' freedom to change the software. The systematic
54 +pattern of such abuse occurs in the area of products for individuals to
55 +use, which is precisely where it is most unacceptable. Therefore, we
56 +have designed this version of the GPL to prohibit the practice for those
57 +products. If such problems arise substantially in other domains, we
58 +stand ready to extend this provision to those domains in future versions
59 +of the GPL, as needed to protect the freedom of users.
60 +
61 + Finally, every program is threatened constantly by software patents.
62 +States should not allow patents to restrict development and use of
63 +software on general-purpose computers, but in those that do, we wish to
64 +avoid the special danger that patents applied to a free program could
65 +make it effectively proprietary. To prevent this, the GPL assures that
66 +patents cannot be used to render the program non-free.
67 +
68 + The precise terms and conditions for copying, distribution and
69 +modification follow.
70 +
71 + TERMS AND CONDITIONS
72 +
73 + 0. Definitions.
74 +
75 + "This License" refers to version 3 of the GNU General Public License.
76 +
77 + "Copyright" also means copyright-like laws that apply to other kinds of
78 +works, such as semiconductor masks.
79 +
80 + "The Program" refers to any copyrightable work licensed under this
81 +License. Each licensee is addressed as "you". "Licensees" and
82 +"recipients" may be individuals or organizations.
83 +
84 + To "modify" a work means to copy from or adapt all or part of the work
85 +in a fashion requiring copyright permission, other than the making of an
86 +exact copy. The resulting work is called a "modified version" of the
87 +earlier work or a work "based on" the earlier work.
88 +
89 + A "covered work" means either the unmodified Program or a work based
90 +on the Program.
91 +
92 + To "propagate" a work means to do anything with it that, without
93 +permission, would make you directly or secondarily liable for
94 +infringement under applicable copyright law, except executing it on a
95 +computer or modifying a private copy. Propagation includes copying,
96 +distribution (with or without modification), making available to the
97 +public, and in some countries other activities as well.
98 +
99 + To "convey" a work means any kind of propagation that enables other
100 +parties to make or receive copies. Mere interaction with a user through
101 +a computer network, with no transfer of a copy, is not conveying.
102 +
103 + An interactive user interface displays "Appropriate Legal Notices"
104 +to the extent that it includes a convenient and prominently visible
105 +feature that (1) displays an appropriate copyright notice, and (2)
106 +tells the user that there is no warranty for the work (except to the
107 +extent that warranties are provided), that licensees may convey the
108 +work under this License, and how to view a copy of this License. If
109 +the interface presents a list of user commands or options, such as a
110 +menu, a prominent item in the list meets this criterion.
111 +
112 + 1. Source Code.
113 +
114 + The "source code" for a work means the preferred form of the work
115 +for making modifications to it. "Object code" means any non-source
116 +form of a work.
117 +
118 + A "Standard Interface" means an interface that either is an official
119 +standard defined by a recognized standards body, or, in the case of
120 +interfaces specified for a particular programming language, one that
121 +is widely used among developers working in that language.
122 +
123 + The "System Libraries" of an executable work include anything, other
124 +than the work as a whole, that (a) is included in the normal form of
125 +packaging a Major Component, but which is not part of that Major
126 +Component, and (b) serves only to enable use of the work with that
127 +Major Component, or to implement a Standard Interface for which an
128 +implementation is available to the public in source code form. A
129 +"Major Component", in this context, means a major essential component
130 +(kernel, window system, and so on) of the specific operating system
131 +(if any) on which the executable work runs, or a compiler used to
132 +produce the work, or an object code interpreter used to run it.
133 +
134 + The "Corresponding Source" for a work in object code form means all
135 +the source code needed to generate, install, and (for an executable
136 +work) run the object code and to modify the work, including scripts to
137 +control those activities. However, it does not include the work's
138 +System Libraries, or general-purpose tools or generally available free
139 +programs which are used unmodified in performing those activities but
140 +which are not part of the work. For example, Corresponding Source
141 +includes interface definition files associated with source files for
142 +the work, and the source code for shared libraries and dynamically
143 +linked subprograms that the work is specifically designed to require,
144 +such as by intimate data communication or control flow between those
145 +subprograms and other parts of the work.
146 +
147 + The Corresponding Source need not include anything that users
148 +can regenerate automatically from other parts of the Corresponding
149 +Source.
150 +
151 + The Corresponding Source for a work in source code form is that
152 +same work.
153 +
154 + 2. Basic Permissions.
155 +
156 + All rights granted under this License are granted for the term of
157 +copyright on the Program, and are irrevocable provided the stated
158 +conditions are met. This License explicitly affirms your unlimited
159 +permission to run the unmodified Program. The output from running a
160 +covered work is covered by this License only if the output, given its
161 +content, constitutes a covered work. This License acknowledges your
162 +rights of fair use or other equivalent, as provided by copyright law.
163 +
164 + You may make, run and propagate covered works that you do not
165 +convey, without conditions so long as your license otherwise remains
166 +in force. You may convey covered works to others for the sole purpose
167 +of having them make modifications exclusively for you, or provide you
168 +with facilities for running those works, provided that you comply with
169 +the terms of this License in conveying all material for which you do
170 +not control copyright. Those thus making or running the covered works
171 +for you must do so exclusively on your behalf, under your direction
172 +and control, on terms that prohibit them from making any copies of
173 +your copyrighted material outside their relationship with you.
174 +
175 + Conveying under any other circumstances is permitted solely under
176 +the conditions stated below. Sublicensing is not allowed; section 10
177 +makes it unnecessary.
178 +
179 + 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
180 +
181 + No covered work shall be deemed part of an effective technological
182 +measure under any applicable law fulfilling obligations under article
183 +11 of the WIPO copyright treaty adopted on 20 December 1996, or
184 +similar laws prohibiting or restricting circumvention of such
185 +measures.
186 +
187 + When you convey a covered work, you waive any legal power to forbid
188 +circumvention of technological measures to the extent such circumvention
189 +is effected by exercising rights under this License with respect to
190 +the covered work, and you disclaim any intention to limit operation or
191 +modification of the work as a means of enforcing, against the work's
192 +users, your or third parties' legal rights to forbid circumvention of
193 +technological measures.
194 +
195 + 4. Conveying Verbatim Copies.
196 +
197 + You may convey verbatim copies of the Program's source code as you
198 +receive it, in any medium, provided that you conspicuously and
199 +appropriately publish on each copy an appropriate copyright notice;
200 +keep intact all notices stating that this License and any
201 +non-permissive terms added in accord with section 7 apply to the code;
202 +keep intact all notices of the absence of any warranty; and give all
203 +recipients a copy of this License along with the Program.
204 +
205 + You may charge any price or no price for each copy that you convey,
206 +and you may offer support or warranty protection for a fee.
207 +
208 + 5. Conveying Modified Source Versions.
209 +
210 + You may convey a work based on the Program, or the modifications to
211 +produce it from the Program, in the form of source code under the
212 +terms of section 4, provided that you also meet all of these conditions:
213 +
214 + a) The work must carry prominent notices stating that you modified
215 + it, and giving a relevant date.
216 +
217 + b) The work must carry prominent notices stating that it is
218 + released under this License and any conditions added under section
219 + 7. This requirement modifies the requirement in section 4 to
220 + "keep intact all notices".
221 +
222 + c) You must license the entire work, as a whole, under this
223 + License to anyone who comes into possession of a copy. This
224 + License will therefore apply, along with any applicable section 7
225 + additional terms, to the whole of the work, and all its parts,
226 + regardless of how they are packaged. This License gives no
227 + permission to license the work in any other way, but it does not
228 + invalidate such permission if you have separately received it.
229 +
230 + d) If the work has interactive user interfaces, each must display
231 + Appropriate Legal Notices; however, if the Program has interactive
232 + interfaces that do not display Appropriate Legal Notices, your
233 + work need not make them do so.
234 +
235 + A compilation of a covered work with other separate and independent
236 +works, which are not by their nature extensions of the covered work,
237 +and which are not combined with it such as to form a larger program,
238 +in or on a volume of a storage or distribution medium, is called an
239 +"aggregate" if the compilation and its resulting copyright are not
240 +used to limit the access or legal rights of the compilation's users
241 +beyond what the individual works permit. Inclusion of a covered work
242 +in an aggregate does not cause this License to apply to the other
243 +parts of the aggregate.
244 +
245 + 6. Conveying Non-Source Forms.
246 +
247 + You may convey a covered work in object code form under the terms
248 +of sections 4 and 5, provided that you also convey the
249 +machine-readable Corresponding Source under the terms of this License,
250 +in one of these ways:
251 +
252 + a) Convey the object code in, or embodied in, a physical product
253 + (including a physical distribution medium), accompanied by the
254 + Corresponding Source fixed on a durable physical medium
255 + customarily used for software interchange.
256 +
257 + b) Convey the object code in, or embodied in, a physical product
258 + (including a physical distribution medium), accompanied by a
259 + written offer, valid for at least three years and valid for as
260 + long as you offer spare parts or customer support for that product
261 + model, to give anyone who possesses the object code either (1) a
262 + copy of the Corresponding Source for all the software in the
263 + product that is covered by this License, on a durable physical
264 + medium customarily used for software interchange, for a price no
265 + more than your reasonable cost of physically performing this
266 + conveying of source, or (2) access to copy the
267 + Corresponding Source from a network server at no charge.
268 +
269 + c) Convey individual copies of the object code with a copy of the
270 + written offer to provide the Corresponding Source. This
271 + alternative is allowed only occasionally and noncommercially, and
272 + only if you received the object code with such an offer, in accord
273 + with subsection 6b.
274 +
275 + d) Convey the object code by offering access from a designated
276 + place (gratis or for a charge), and offer equivalent access to the
277 + Corresponding Source in the same way through the same place at no
278 + further charge. You need not require recipients to copy the
279 + Corresponding Source along with the object code. If the place to
280 + copy the object code is a network server, the Corresponding Source
281 + may be on a different server (operated by you or a third party)
282 + that supports equivalent copying facilities, provided you maintain
283 + clear directions next to the object code saying where to find the
284 + Corresponding Source. Regardless of what server hosts the
285 + Corresponding Source, you remain obligated to ensure that it is
286 + available for as long as needed to satisfy these requirements.
287 +
288 + e) Convey the object code using peer-to-peer transmission, provided
289 + you inform other peers where the object code and Corresponding
290 + Source of the work are being offered to the general public at no
291 + charge under subsection 6d.
292 +
293 + A separable portion of the object code, whose source code is excluded
294 +from the Corresponding Source as a System Library, need not be
295 +included in conveying the object code work.
296 +
297 + A "User Product" is either (1) a "consumer product", which means any
298 +tangible personal property which is normally used for personal, family,
299 +or household purposes, or (2) anything designed or sold for incorporation
300 +into a dwelling. In determining whether a product is a consumer product,
301 +doubtful cases shall be resolved in favor of coverage. For a particular
302 +product received by a particular user, "normally used" refers to a
303 +typical or common use of that class of product, regardless of the status
304 +of the particular user or of the way in which the particular user
305 +actually uses, or expects or is expected to use, the product. A product
306 +is a consumer product regardless of whether the product has substantial
307 +commercial, industrial or non-consumer uses, unless such uses represent
308 +the only significant mode of use of the product.
309 +
310 + "Installation Information" for a User Product means any methods,
311 +procedures, authorization keys, or other information required to install
312 +and execute modified versions of a covered work in that User Product from
313 +a modified version of its Corresponding Source. The information must
314 +suffice to ensure that the continued functioning of the modified object
315 +code is in no case prevented or interfered with solely because
316 +modification has been made.
317 +
318 + If you convey an object code work under this section in, or with, or
319 +specifically for use in, a User Product, and the conveying occurs as
320 +part of a transaction in which the right of possession and use of the
321 +User Product is transferred to the recipient in perpetuity or for a
322 +fixed term (regardless of how the transaction is characterized), the
323 +Corresponding Source conveyed under this section must be accompanied
324 +by the Installation Information. But this requirement does not apply
325 +if neither you nor any third party retains the ability to install
326 +modified object code on the User Product (for example, the work has
327 +been installed in ROM).
328 +
329 + The requirement to provide Installation Information does not include a
330 +requirement to continue to provide support service, warranty, or updates
331 +for a work that has been modified or installed by the recipient, or for
332 +the User Product in which it has been modified or installed. Access to a
333 +network may be denied when the modification itself materially and
334 +adversely affects the operation of the network or violates the rules and
335 +protocols for communication across the network.
336 +
337 + Corresponding Source conveyed, and Installation Information provided,
338 +in accord with this section must be in a format that is publicly
339 +documented (and with an implementation available to the public in
340 +source code form), and must require no special password or key for
341 +unpacking, reading or copying.
342 +
343 + 7. Additional Terms.
344 +
345 + "Additional permissions" are terms that supplement the terms of this
346 +License by making exceptions from one or more of its conditions.
347 +Additional permissions that are applicable to the entire Program shall
348 +be treated as though they were included in this License, to the extent
349 +that they are valid under applicable law. If additional permissions
350 +apply only to part of the Program, that part may be used separately
351 +under those permissions, but the entire Program remains governed by
352 +this License without regard to the additional permissions.
353 +
354 + When you convey a copy of a covered work, you may at your option
355 +remove any additional permissions from that copy, or from any part of
356 +it. (Additional permissions may be written to require their own
357 +removal in certain cases when you modify the work.) You may place
358 +additional permissions on material, added by you to a covered work,
359 +for which you have or can give appropriate copyright permission.
360 +
361 + Notwithstanding any other provision of this License, for material you
362 +add to a covered work, you may (if authorized by the copyright holders of
363 +that material) supplement the terms of this License with terms:
364 +
365 + a) Disclaiming warranty or limiting liability differently from the
366 + terms of sections 15 and 16 of this License; or
367 +
368 + b) Requiring preservation of specified reasonable legal notices or
369 + author attributions in that material or in the Appropriate Legal
370 + Notices displayed by works containing it; or
371 +
372 + c) Prohibiting misrepresentation of the origin of that material, or
373 + requiring that modified versions of such material be marked in
374 + reasonable ways as different from the original version; or
375 +
376 + d) Limiting the use for publicity purposes of names of licensors or
377 + authors of the material; or
378 +
379 + e) Declining to grant rights under trademark law for use of some
380 + trade names, trademarks, or service marks; or
381 +
382 + f) Requiring indemnification of licensors and authors of that
383 + material by anyone who conveys the material (or modified versions of
384 + it) with contractual assumptions of liability to the recipient, for
385 + any liability that these contractual assumptions directly impose on
386 + those licensors and authors.
387 +
388 + All other non-permissive additional terms are considered "further
389 +restrictions" within the meaning of section 10. If the Program as you
390 +received it, or any part of it, contains a notice stating that it is
391 +governed by this License along with a term that is a further
392 +restriction, you may remove that term. If a license document contains
393 +a further restriction but permits relicensing or conveying under this
394 +License, you may add to a covered work material governed by the terms
395 +of that license document, provided that the further restriction does
396 +not survive such relicensing or conveying.
397 +
398 + If you add terms to a covered work in accord with this section, you
399 +must place, in the relevant source files, a statement of the
400 +additional terms that apply to those files, or a notice indicating
401 +where to find the applicable terms.
402 +
403 + Additional terms, permissive or non-permissive, may be stated in the
404 +form of a separately written license, or stated as exceptions;
405 +the above requirements apply either way.
406 +
407 + 8. Termination.
408 +
409 + You may not propagate or modify a covered work except as expressly
410 +provided under this License. Any attempt otherwise to propagate or
411 +modify it is void, and will automatically terminate your rights under
412 +this License (including any patent licenses granted under the third
413 +paragraph of section 11).
414 +
415 + However, if you cease all violation of this License, then your
416 +license from a particular copyright holder is reinstated (a)
417 +provisionally, unless and until the copyright holder explicitly and
418 +finally terminates your license, and (b) permanently, if the copyright
419 +holder fails to notify you of the violation by some reasonable means
420 +prior to 60 days after the cessation.
421 +
422 + Moreover, your license from a particular copyright holder is
423 +reinstated permanently if the copyright holder notifies you of the
424 +violation by some reasonable means, this is the first time you have
425 +received notice of violation of this License (for any work) from that
426 +copyright holder, and you cure the violation prior to 30 days after
427 +your receipt of the notice.
428 +
429 + Termination of your rights under this section does not terminate the
430 +licenses of parties who have received copies or rights from you under
431 +this License. If your rights have been terminated and not permanently
432 +reinstated, you do not qualify to receive new licenses for the same
433 +material under section 10.
434 +
435 + 9. Acceptance Not Required for Having Copies.
436 +
437 + You are not required to accept this License in order to receive or
438 +run a copy of the Program. Ancillary propagation of a covered work
439 +occurring solely as a consequence of using peer-to-peer transmission
440 +to receive a copy likewise does not require acceptance. However,
441 +nothing other than this License grants you permission to propagate or
442 +modify any covered work. These actions infringe copyright if you do
443 +not accept this License. Therefore, by modifying or propagating a
444 +covered work, you indicate your acceptance of this License to do so.
445 +
446 + 10. Automatic Licensing of Downstream Recipients.
447 +
448 + Each time you convey a covered work, the recipient automatically
449 +receives a license from the original licensors, to run, modify and
450 +propagate that work, subject to this License. You are not responsible
451 +for enforcing compliance by third parties with this License.
452 +
453 + An "entity transaction" is a transaction transferring control of an
454 +organization, or substantially all assets of one, or subdividing an
455 +organization, or merging organizations. If propagation of a covered
456 +work results from an entity transaction, each party to that
457 +transaction who receives a copy of the work also receives whatever
458 +licenses to the work the party's predecessor in interest had or could
459 +give under the previous paragraph, plus a right to possession of the
460 +Corresponding Source of the work from the predecessor in interest, if
461 +the predecessor has it or can get it with reasonable efforts.
462 +
463 + You may not impose any further restrictions on the exercise of the
464 +rights granted or affirmed under this License. For example, you may
465 +not impose a license fee, royalty, or other charge for exercise of
466 +rights granted under this License, and you may not initiate litigation
467 +(including a cross-claim or counterclaim in a lawsuit) alleging that
468 +any patent claim is infringed by making, using, selling, offering for
469 +sale, or importing the Program or any portion of it.
470 +
471 + 11. Patents.
472 +
473 + A "contributor" is a copyright holder who authorizes use under this
474 +License of the Program or a work on which the Program is based. The
475 +work thus licensed is called the contributor's "contributor version".
476 +
477 + A contributor's "essential patent claims" are all patent claims
478 +owned or controlled by the contributor, whether already acquired or
479 +hereafter acquired, that would be infringed by some manner, permitted
480 +by this License, of making, using, or selling its contributor version,
481 +but do not include claims that would be infringed only as a
482 +consequence of further modification of the contributor version. For
483 +purposes of this definition, "control" includes the right to grant
484 +patent sublicenses in a manner consistent with the requirements of
485 +this License.
486 +
487 + Each contributor grants you a non-exclusive, worldwide, royalty-free
488 +patent license under the contributor's essential patent claims, to
489 +make, use, sell, offer for sale, import and otherwise run, modify and
490 +propagate the contents of its contributor version.
491 +
492 + In the following three paragraphs, a "patent license" is any express
493 +agreement or commitment, however denominated, not to enforce a patent
494 +(such as an express permission to practice a patent or covenant not to
495 +sue for patent infringement). To "grant" such a patent license to a
496 +party means to make such an agreement or commitment not to enforce a
497 +patent against the party.
498 +
499 + If you convey a covered work, knowingly relying on a patent license,
500 +and the Corresponding Source of the work is not available for anyone
501 +to copy, free of charge and under the terms of this License, through a
502 +publicly available network server or other readily accessible means,
503 +then you must either (1) cause the Corresponding Source to be so
504 +available, or (2) arrange to deprive yourself of the benefit of the
505 +patent license for this particular work, or (3) arrange, in a manner
506 +consistent with the requirements of this License, to extend the patent
507 +license to downstream recipients. "Knowingly relying" means you have
508 +actual knowledge that, but for the patent license, your conveying the
509 +covered work in a country, or your recipient's use of the covered work
510 +in a country, would infringe one or more identifiable patents in that
511 +country that you have reason to believe are valid.
512 +
513 + If, pursuant to or in connection with a single transaction or
514 +arrangement, you convey, or propagate by procuring conveyance of, a
515 +covered work, and grant a patent license to some of the parties
516 +receiving the covered work authorizing them to use, propagate, modify
517 +or convey a specific copy of the covered work, then the patent license
518 +you grant is automatically extended to all recipients of the covered
519 +work and works based on it.
520 +
521 + A patent license is "discriminatory" if it does not include within
522 +the scope of its coverage, prohibits the exercise of, or is
523 +conditioned on the non-exercise of one or more of the rights that are
524 +specifically granted under this License. You may not convey a covered
525 +work if you are a party to an arrangement with a third party that is
526 +in the business of distributing software, under which you make payment
527 +to the third party based on the extent of your activity of conveying
528 +the work, and under which the third party grants, to any of the
529 +parties who would receive the covered work from you, a discriminatory
530 +patent license (a) in connection with copies of the covered work
531 +conveyed by you (or copies made from those copies), or (b) primarily
532 +for and in connection with specific products or compilations that
533 +contain the covered work, unless you entered into that arrangement,
534 +or that patent license was granted, prior to 28 March 2007.
535 +
536 + Nothing in this License shall be construed as excluding or limiting
537 +any implied license or other defenses to infringement that may
538 +otherwise be available to you under applicable patent law.
539 +
540 + 12. No Surrender of Others' Freedom.
541 +
542 + If conditions are imposed on you (whether by court order, agreement or
543 +otherwise) that contradict the conditions of this License, they do not
544 +excuse you from the conditions of this License. If you cannot convey a
545 +covered work so as to satisfy simultaneously your obligations under this
546 +License and any other pertinent obligations, then as a consequence you may
547 +not convey it at all. For example, if you agree to terms that obligate you
548 +to collect a royalty for further conveying from those to whom you convey
549 +the Program, the only way you could satisfy both those terms and this
550 +License would be to refrain entirely from conveying the Program.
551 +
552 + 13. Use with the GNU Affero General Public License.
553 +
554 + Notwithstanding any other provision of this License, you have
555 +permission to link or combine any covered work with a work licensed
556 +under version 3 of the GNU Affero General Public License into a single
557 +combined work, and to convey the resulting work. The terms of this
558 +License will continue to apply to the part which is the covered work,
559 +but the special requirements of the GNU Affero General Public License,
560 +section 13, concerning interaction through a network will apply to the
561 +combination as such.
562 +
563 + 14. Revised Versions of this License.
564 +
565 + The Free Software Foundation may publish revised and/or new versions of
566 +the GNU General Public License from time to time. Such new versions will
567 +be similar in spirit to the present version, but may differ in detail to
568 +address new problems or concerns.
569 +
570 + Each version is given a distinguishing version number. If the
571 +Program specifies that a certain numbered version of the GNU General
572 +Public License "or any later version" applies to it, you have the
573 +option of following the terms and conditions either of that numbered
574 +version or of any later version published by the Free Software
575 +Foundation. If the Program does not specify a version number of the
576 +GNU General Public License, you may choose any version ever published
577 +by the Free Software Foundation.
578 +
579 + If the Program specifies that a proxy can decide which future
580 +versions of the GNU General Public License can be used, that proxy's
581 +public statement of acceptance of a version permanently authorizes you
582 +to choose that version for the Program.
583 +
584 + Later license versions may give you additional or different
585 +permissions. However, no additional obligations are imposed on any
586 +author or copyright holder as a result of your choosing to follow a
587 +later version.
588 +
589 + 15. Disclaimer of Warranty.
590 +
591 + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
592 +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
593 +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
594 +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
595 +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
596 +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
597 +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
598 +ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
599 +
600 + 16. Limitation of Liability.
601 +
602 + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
603 +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
604 +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
605 +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
606 +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
607 +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
608 +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
609 +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
610 +SUCH DAMAGES.
611 +
612 + 17. Interpretation of Sections 15 and 16.
613 +
614 + If the disclaimer of warranty and limitation of liability provided
615 +above cannot be given local legal effect according to their terms,
616 +reviewing courts shall apply local law that most closely approximates
617 +an absolute waiver of all civil liability in connection with the
618 +Program, unless a warranty or assumption of liability accompanies a
619 +copy of the Program in return for a fee.
620 +
621 + END OF TERMS AND CONDITIONS
622 +
623 + How to Apply These Terms to Your New Programs
624 +
625 + If you develop a new program, and you want it to be of the greatest
626 +possible use to the public, the best way to achieve this is to make it
627 +free software which everyone can redistribute and change under these terms.
628 +
629 + To do so, attach the following notices to the program. It is safest
630 +to attach them to the start of each source file to most effectively
631 +state the exclusion of warranty; and each file should have at least
632 +the "copyright" line and a pointer to where the full notice is found.
633 +
634 + {one line to give the program's name and a brief idea of what it does.}
635 + Copyright (C) {year} {name of author}
636 +
637 + This program is free software: you can redistribute it and/or modify
638 + it under the terms of the GNU General Public License as published by
639 + the Free Software Foundation, either version 3 of the License, or
640 + (at your option) any later version.
641 +
642 + This program is distributed in the hope that it will be useful,
643 + but WITHOUT ANY WARRANTY; without even the implied warranty of
644 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
645 + GNU General Public License for more details.
646 +
647 + You should have received a copy of the GNU General Public License
648 + along with this program. If not, see <http://www.gnu.org/licenses/>.
649 +
650 +Also add information on how to contact you by electronic and paper mail.
651 +
652 + If the program does terminal interaction, make it output a short
653 +notice like this when it starts in an interactive mode:
654 +
655 + {project} Copyright (C) {year} {fullname}
656 + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
657 + This is free software, and you are welcome to redistribute it
658 + under certain conditions; type `show c' for details.
659 +
660 +The hypothetical commands `show w' and `show c' should show the appropriate
661 +parts of the General Public License. Of course, your program's commands
662 +might be different; for a GUI interface, you would use an "about box".
663 +
664 + You should also get your employer (if you work as a programmer) or school,
665 +if any, to sign a "copyright disclaimer" for the program, if necessary.
666 +For more information on this, and how to apply and follow the GNU GPL, see
667 +<http://www.gnu.org/licenses/>.
668 +
669 + The GNU General Public License does not permit incorporating your program
670 +into proprietary programs. If your program is a subroutine library, you
671 +may consider it more useful to permit linking proprietary applications with
672 +the library. If this is what you want to do, use the GNU Lesser General
673 +Public License instead of this License. But first, please read
674 +<http://www.gnu.org/philosophy/why-not-lgpl.html>.
rdp/README.md new
+10
@@ -0,0 +1,10 @@
1 +node-rdpjs
2 +==========
3 +
4 +This folder contains a fork of the node-rdpjs2 package which is identical to [node-rdpjs](github.com/citronneur/node-rdpjs) v0.2.1 but just updated for
5 +latest versions of Node along with more modifications to remove dependencies and more importantly, added support for Network Layer Authentication (NLA).
6 +
7 +NLA support was ported from [RDP-RS](https://github.com/citronneur/rdp-rs) which is a Rust RDP solution by the same author as node-rdpjs.
8 +
9 +The license for node-rdpjs is GPL 3.0 and is limited the the "rdp" folder. If this is a concern, you can delete the "rdp" folder and MeshCentral will
10 +still work perfectly without RDP functionality.
\ No newline at end of file
rdp/asn1/ber.js new
+111
@@ -0,0 +1,111 @@
1 +/*
2 + * Copyright (c) 2014-2015 Sylvain Peyrefitte
3 + *
4 + * This file is part of node-rdpjs.
5 + *
6 + * node-rdpjs is free software: you can redistribute it and/or modify
7 + * it under the terms of the GNU General Public License as published by
8 + * the Free Software Foundation, either version 3 of the License, or
9 + * (at your option) any later version.
10 + *
11 + * This program is distributed in the hope that it will be useful,
12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 + * GNU General Public License for more details.
15 + *
16 + * You should have received a copy of the GNU General Public License
17 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 + */
19 +
20 +var type = require('../core').type;
21 +var log = require('../core').log;
22 +var error = require('../core').error;
23 +
24 +/**
25 + * Parse tag(T) field of BER TLV
26 + * And check with expected tag
27 + * @param s {type.Stream}
28 + * @param tag {spec.tag}
29 + * @returns {Boolean} True for valid tag matching
30 + */
31 +function decodeTag(s, tag) {
32 + var nextTag = new type.UInt8().read(s).value;
33 + if (tag.tagNumber > 30) {
34 + nextTagNumber = new type.UInt8().read(s).value;
35 + }
36 + else {
37 + nextTagNumber = nextTag & 0x1F;
38 + }
39 +
40 + return ((nextTag & 0xE0) === (tag.tagClass | tag.tagFormat)) && (nextTagNumber === tag.tagNumber);
41 +};
42 +
43 +/**
44 + * Parse length(L) field of BER TLV
45 + * @param s {type.Stream}
46 + * @returns {integer}
47 + */
48 +function decodeLength(s) {
49 + var size = new type.UInt8().read(s).value;
50 + if(size & 0x80) {
51 + size &= ~0x80;
52 + if(size === 1) {
53 + size = new type.UInt8().read(s).value;
54 + }
55 + else if(size === 2) {
56 + size = new type.UInt16Be().read(s).value;
57 + }
58 + else{
59 + throw new error.ProtocolError('NODE_RDP_ASN1_BER_INVALID_LENGTH');
60 + }
61 + }
62 + return size;
63 +};
64 +
65 +/**
66 + * Decode tuple TLV (Tag Length Value) of BER
67 + * @param s {type.Stream}
68 + * @param tag {spec.Asn1Tag} expected tag
69 + * @returns {type.BinaryString} Value of tuple
70 + */
71 +function decode(s, tag) {
72 + if (!decodeTag(s, tag)) {
73 + throw new error.ProtocolError('NODE_RDP_ASN1_BER_INVALID_TAG');
74 + }
75 + var length = decodeLength(s);
76 +
77 + if (length === 0) {
78 + return new type.Stream(0);
79 + }
80 + return new type.BinaryString(null,{ readLength : new type.CallableValue(length) }).read(s);
81 +};
82 +
83 +function encodeTag(tag) {
84 + if(tag.tagNumber > 30) {
85 + return new type.Component([new type.UInt8(tag.tagClass | tag.tagFormat | 0x1F), new type.UInt8(tag.tagNumber)]);
86 + }
87 + else {
88 + return new type.UInt8((tag.tagClass | tag.tagFormat) | (tag.tagNumber & 0x1F));
89 + }
90 +}
91 +
92 +function encodeLength(length) {
93 + if(length > 0x7f) {
94 + return new type.Component([new type.UInt8(0x82), new type.UInt16Be(length)]);
95 + }
96 + else {
97 + return new type.UInt8(length);
98 + }
99 +}
100 +
101 +function encode(tag, buffer) {
102 + return new type.Component([encodeTag(tag), encodeLength(buffer.size()), buffer]);
103 +}
104 +
105 +/**
106 + * Module Export
107 + */
108 +module.exports = {
109 + decode : decode,
110 + encode : encode
111 +};
rdp/asn1/index.js new
+28
@@ -0,0 +1,28 @@
1 +/*
2 + * Copyright (c) 2014-2015 Sylvain Peyrefitte
3 + *
4 + * This file is part of node-rdpjs.
5 + *
6 + * node-rdpjs is free software: you can redistribute it and/or modify
7 + * it under the terms of the GNU General Public License as published by
8 + * the Free Software Foundation, either version 3 of the License, or
9 + * (at your option) any later version.
10 + *
11 + * This program is distributed in the hope that it will be useful,
12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 + * GNU General Public License for more details.
15 + *
16 + * You should have received a copy of the GNU General Public License
17 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 + */
19 +
20 +var ber = require('./ber');
21 +var univ = require('./univ');
22 +var spec = require('./spec');
23 +
24 +module.exports = {
25 + ber : ber,
26 + univ : univ,
27 + spec : spec
28 +};
rdp/asn1/spec.js new
+139
@@ -0,0 +1,139 @@
1 +/*
2 + * Copyright (c) 2014-2015 Sylvain Peyrefitte
3 + *
4 + * This file is part of node-rdpjs.
5 + *
6 + * node-rdpjs is free software: you can redistribute it and/or modify
7 + * it under the terms of the GNU General Public License as published by
8 + * the Free Software Foundation, either version 3 of the License, or
9 + * (at your option) any later version.
10 + *
11 + * This program is distributed in the hope that it will be useful,
12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 + * GNU General Public License for more details.
15 + *
16 + * You should have received a copy of the GNU General Public License
17 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 + */
19 +
20 +var inherits = require('util').inherits;
21 +var type = require('../core').type;
22 +var error = require('../core').error;
23 +
24 +/**
25 + * Tag Class
26 + */
27 +var TagClass = {
28 + Universal : 0x00,
29 + Application : 0x40,
30 + Context : 0x80,
31 + Private : 0xC0
32 +};
33 +
34 +/**
35 + * Tag Format
36 + */
37 +var TagFormat = {
38 + Primitive : 0x00,
39 + Constructed : 0x20
40 +};
41 +
42 +/**
43 + * ASN.1 tag
44 + * @param tagClass {TagClass}
45 + * @param tagFormat {TagFormat}
46 + * @param tagNumber {integer}
47 + */
48 +function Asn1Tag(tagClass, tagFormat, tagNumber) {
49 + this.tagClass = tagClass;
50 + this.tagFormat = tagFormat;
51 + this.tagNumber = tagNumber;
52 +}
53 +
54 +/**
55 + * ASN.1 Specification
56 + * @param tag {Asn1Tag}
57 + */
58 +function Asn1Spec(tag) {
59 + this.tag = tag;
60 + this.opt = false;
61 +}
62 +
63 +/**
64 + * Add an implicit tag
65 + * override tag
66 + * @param tag {Asn1Tag}
67 + * @returns {Asn1Spec}
68 + */
69 +Asn1Spec.prototype.implicitTag = function(tag) {
70 + this.tag = tag;
71 + return this;
72 +};
73 +
74 +/**
75 + * Set optional to true
76 + * @returns {Asn1Spec}
77 + */
78 +Asn1Spec.prototype.optional = function() {
79 + this.opt = true;
80 + return this;
81 +};
82 +
83 +/**
84 + * Add explicit tag
85 + * Append new tag header to existing tag
86 + * @param tag {Asn1Tag}
87 + * @returns {Asn1SpecExplicitTag}
88 + */
89 +Asn1Spec.prototype.explicitTag = function(tag) {
90 + return new Asn1SpecExplicitTag(tag, this);
91 +};
92 +
93 +/**
94 + * Decode must be implemented by all sub type
95 + * @param s {type.Stream}
96 + * @param decoder
97 + */
98 +Asn1Spec.prototype.decode = function(s, decoder) {
99 + throw new error.FatalError('NODE_RDP_AS1_SPEC_DECODE_NOT_IMPLEMENTED');
100 +};
101 +
102 +/**
103 + * Encode must be implemented by all sub type
104 + * @param decoder
105 + */
106 +Asn1Spec.prototype.encode = function(encoder) {
107 + throw new error.FatalError('NODE_RDP_AS1_SPEC_ENCODE_NOT_IMPLEMENTED');
108 +};
109 +
110 +/**
111 + * Component Asn1Spec object
112 + */
113 +function Asn1SpecExplicitTag(tag, spec) {
114 + Asn1Spec.call(this, tag);
115 + this.spec = spec;
116 +}
117 +
118 +inherits(Asn1SpecExplicitTag, Asn1Spec);
119 +
120 +/**
121 + * Decode first header
122 + * @param s {type.Stream}
123 + * @param decoder
124 + */
125 +Asn1Spec.prototype.decode = function(s, decoder) {
126 + var specStream = new type.Stream(decoder.decode(s, this.tag).value);
127 + this.spec.decode(specStream, decoder);
128 +};
129 +
130 +/**
131 + * Module exports
132 + */
133 +module.exports = {
134 + TagClass : TagClass,
135 + TagFormat : TagFormat,
136 + Asn1Tag : Asn1Tag,
137 + Asn1Spec : Asn1Spec,
138 + Asn1SpecExplicitTag : Asn1SpecExplicitTag
139 +};
rdp/asn1/univ.js new
+606
@@ -0,0 +1,606 @@
1 +/*
2 + * Copyright (c) 2014-2015 Sylvain Peyrefitte
3 + *
4 + * This file is part of node-rdpjs.
5 + *
6 + * node-rdpjs is free software: you can redistribute it and/or modify
7 + * it under the terms of the GNU General Public License as published by
8 + * the Free Software Foundation, either version 3 of the License, or
9 + * (at your option) any later version.
10 + *
11 + * This program is distributed in the hope that it will be useful,
12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 + * GNU General Public License for more details.
15 + *
16 + * You should have received a copy of the GNU General Public License
17 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 + */
19 +
20 +var spec = require('./spec');
21 +var type = require('../core').type;
22 +var error = require('../core').error;
23 +var inherits = require('util').inherits;
24 +
25 +/**
26 + * ASN.1 Universal tags
27 + * @see http://www.obj-sys.com/asn1tutorial/node124.html
28 + */
29 +var UniversalTag = {
30 + Boolean : 1,
31 + Integer : 2,
32 + BitString : 3,
33 + OctetString : 4,
34 + Null : 5,
35 + ObjectIdentifier : 6,
36 + ObjectDescriptor : 7,
37 + Enumerate : 10,
38 + UTF8String : 12,
39 + Sequence : 16,
40 + Set : 17,
41 + PrintableString : 19,
42 + T61String : 20,
43 + IA5String : 22,
44 + UTCTime : 23,
45 + GeneralizedTime : 24,
46 + UniversalString : 28,
47 + BMPString : 30
48 +};
49 +
50 +/**
51 + * Boolean type
52 + * @param value {boolean} inner value
53 + */
54 +function Boolean(value) {
55 + spec.Asn1Spec.call(this, new spec.Asn1Tag(spec.TagClass.Universal, spec.TagFormat.Primitive, UniversalTag.Boolean));
56 + this.value = value || false;
57 +}
58 +
59 +inherits(Boolean, spec.Asn1Spec);
60 +
61 +/**
62 + * @param s {type.Stream}
63 + * @param decoder {ber.decoder}
64 + * @returns {Boolean}
65 + */
66 +Boolean.prototype.decode = function(s, decoder) {
67 + this.value = new type.UInt8().read(new type.Stream(decoder.decode(s, this.tag).value)).value !== 0;
68 + return this;
69 +};
70 +
71 +/**
72 + * @param decoder {ber.decoder}
73 + * @returns {type.*}
74 + */
75 +Boolean.prototype.encode = function(encoder) {
76 + if(this.value) {
77 + return encoder.encode(this.tag, new type.UInt8(0xff));
78 + }
79 + else {
80 + return encoder.encode(this.tag, new type.UInt8(0));
81 + }
82 +};
83 +
84 +/**
85 + * Integer type
86 + * @param value {integer | Buffer}
87 + */
88 +function Integer(value) {
89 + spec.Asn1Spec.call(this, new spec.Asn1Tag(spec.TagClass.Universal, spec.TagFormat.Primitive, UniversalTag.Integer));
90 + this.value = value || 0;
91 +}
92 +
93 +inherits(Integer, spec.Asn1Spec);
94 +
95 +/**
96 + * @param s {type.Stream}
97 + * @param decoder {ber.decoder}
98 + * @returns {Integer}
99 + */
100 +Integer.prototype.decode = function(s, decoder) {
101 + var integerBuffer = decoder.decode(s, this.tag).value;
102 + if(integerBuffer.length < 5) {
103 + var integerStream = new type.Stream(integerBuffer);
104 + while (integerStream.availableLength() > 0) {
105 + this.value = this.value << 8;
106 + this.value |= new type.UInt8().read(integerStream).value;
107 + }
108 + }
109 + // bignum case
110 + else {
111 + this.value = integerBuffer;
112 + }
113 + return this;
114 +};
115 +
116 +/**
117 + * @param encoder {ber.decoder}
118 + * @returns {type.*}
119 + */
120 +Integer.prototype.encode = function(encoder) {
121 + if(this.value <= 0xff) {
122 + return encoder.encode(this.tag, new type.UInt8(this.value));
123 + }
124 + else if(this.value <= 0xffff) {
125 + return encoder.encode(this.tag, new type.UInt16Be(this.value));
126 + }
127 + else {
128 + return encoder.encode(this.tag, new type.UInt32Be(this.value));
129 + }
130 +};
131 +
132 +/**
133 + * Sequence type
134 + * @param value {object}
135 + */
136 +function Sequence(value) {
137 + spec.Asn1Spec.call(this, new spec.Asn1Tag(spec.TagClass.Universal, spec.TagFormat.Constructed, UniversalTag.Sequence));
138 + this.value = value || [];
139 +}
140 +
141 +inherits(Sequence, spec.Asn1Spec);
142 +
143 +/**
144 + * @param s {type.Stream}
145 + * @param decoder {ber.decoder}
146 + * @returns {Sequence}
147 + */
148 +Sequence.prototype.decode = function(s, decoder) {
149 + var sequenceStream = new type.Stream(decoder.decode(s, this.tag).value);
150 + for (var i in this.value) {
151 + var rec = sequenceStream.offset;
152 + try {
153 + this.value[i].decode(sequenceStream, decoder);
154 + } catch(e) {
155 + if ((e.message === 'NODE_RDP_ASN1_BER_INVALID_TAG') && !this.value[i].opt) {
156 + throw new error.ProtocolError('NODE_RDP_ASN1_UNIV_SEQUENCE_FIELD_NOT_PRESENT');
157 + }
158 + sequenceStream.offset = rec;
159 + }
160 + }
161 + return this;
162 +};
163 +
164 +/**
165 + * Encode sequence
166 + * @param encoder
167 + * @returns {type.Component}
168 + */
169 +Sequence.prototype.encode = function(encoder) {
170 + var sequence = new type.Component([]);
171 + for (var i in this.value) {
172 + sequence.obj.push(this.value[i].encode(encoder))
173 + }
174 + return encoder.encode(this.tag, sequence);
175 +};
176 +
177 +
178 +/**
179 + * Enumerate type
180 + * @param value {integer}
181 + */
182 +function Enumerate(value) {
183 + spec.Asn1Spec.call(this, new spec.Asn1Tag(spec.TagClass.Universal, spec.TagFormat.Primitive, UniversalTag.Enumerate));
184 + this.value = value || 0;
185 +}
186 +
187 +inherits(Enumerate, spec.Asn1Spec);
188 +
189 +/**
190 + * @param s {type.Stream}
191 + * @param decoder {ber.decoder}
192 + * @returns {Enumerate}
193 + */
194 +Enumerate.prototype.decode = function(s, decoder) {
195 + this.value = new type.UInt8().read(new type.Stream(decoder.decode(s, this.tag).value)).value;
196 + return this;
197 +};
198 +
199 +/**
200 + * Encode enumerate type
201 + * @param encoder
202 + * @returns {type.Component}
203 + */
204 +Enumerate.prototype.encode = function(encoder) {
205 + return encoder.encode(this.tag, new type.UInt8(this.value));
206 +};
207 +
208 +/**
209 + * OctetString type
210 + * @param value {Buffer}
211 + */
212 +function OctetString(value) {
213 + spec.Asn1Spec.call(this, new spec.Asn1Tag(spec.TagClass.Universal, spec.TagFormat.Primitive, UniversalTag.OctetString));
214 + this.value = value || Buffer.alloc(0);
215 +}
216 +
217 +inherits(OctetString, spec.Asn1Spec);
218 +
219 +/**
220 + * @param s {type.Stream}
221 + * @param decoder {ber.decoder}
222 + * @returns {OctetString}
223 + */
224 +OctetString.prototype.decode = function(s, decoder) {
225 + this.value = decoder.decode(s, this.tag).value;
226 + return this;
227 +};
228 +
229 +/**
230 + * Encode Octet String
231 + * @param encoder
232 + * @returns {type.Component}
233 + */
234 +OctetString.prototype.encode = function(encoder) {
235 + return encoder.encode(this.tag, new type.BinaryString(this.value));
236 +};
237 +
238 +/**
239 + * ObjectIdentifier type
240 + * @param value {Buffer}
241 + */
242 +function ObjectIdentifier(value) {
243 + spec.Asn1Spec.call(this, new spec.Asn1Tag(spec.TagClass.Universal, spec.TagFormat.Primitive, UniversalTag.ObjectIdentifier));
244 + this.value = value || Buffer.alloc(5);
245 +}
246 +
247 +inherits(ObjectIdentifier, spec.Asn1Spec);
248 +
249 +/**
250 + * @param s {type.Stream}
251 + * @param decoder {ber.decoder}
252 + * @returns {ObjectIdentifier}
253 + */
254 +ObjectIdentifier.prototype.decode = function(s, decoder) {
255 + this.value = decoder.decode(s, this.tag).value;
256 + return this;
257 +};
258 +
259 +/**
260 + * Null type
261 + */
262 +function Null() {
263 + spec.Asn1Spec.call(this, new spec.Asn1Tag(spec.TagClass.Universal, spec.TagFormat.Primitive, UniversalTag.Null));
264 +}
265 +
266 +inherits(Null, spec.Asn1Spec);
267 +
268 +/**
269 + * @param s {type.Stream}
270 + * @param decoder {ber.decoder}
271 + * @returns {Null}
272 + */
273 +Null.prototype.decode = function(s, decoder) {
274 + decoder.decode(s, this.tag);
275 + return this;
276 +};
277 +
278 +/**
279 + * Choice type
280 + * @param value {object} list of available type
281 + */
282 +function Choice(value) {
283 + // not tagged type
284 + spec.Asn1Spec.call(this, new spec.Asn1Tag());
285 + this.value = value;
286 +}
287 +
288 +inherits(Choice, spec.Asn1Spec);
289 +
290 +/**
291 + * @param s {type.Stream}
292 + * @param decoder {ber.decoder}
293 + * @returns {Choice}
294 + */
295 +Choice.prototype.decode = function(s, decoder) {
296 + for (var i in this.value) {
297 + var rec = s.offset;
298 + try {
299 + this.value[i].decode(s, decoder);
300 + break;
301 + }
302 + catch(e) {
303 + s.offset = rec;
304 + }
305 + }
306 + return this;
307 +};
308 +
309 +/**
310 + * SetOf type
311 + * @param factory {function} type builder
312 + * @param value {object} list of available type
313 + */
314 +function SetOf(factory, value) {
315 + // not tagged type
316 + spec.Asn1Spec.call(this, new spec.Asn1Tag(spec.TagClass.Universal, spec.TagFormat.Constructed, UniversalTag.Set));
317 + this.factory = factory;
318 + this.value = value || [];
319 +}
320 +
321 +inherits(SetOf, spec.Asn1Spec);
322 +
323 +/**
324 + * @param s {type.Stream}
325 + * @param decoder {ber.decoder}
326 + * @returns {SetOf}
327 + */
328 +SetOf.prototype.decode = function(s, decoder) {
329 + var setOfStream = new type.Stream(decoder.decode(s, this.tag).value);
330 + while (setOfStream.availableLength() > 0) {
331 + this.value.push(this.factory().decode(setOfStream, decoder));
332 + }
333 + return this;
334 +};
335 +
336 +/**
337 + * SequenceOf type
338 + * @param factory {function} type builder
339 + * @param value {object} list of available type
340 + */
341 +function SequenceOf(factory, value) {
342 + // not tagged type
343 + spec.Asn1Spec.call(this, new spec.Asn1Tag(spec.TagClass.Universal, spec.TagFormat.Constructed, UniversalTag.Sequence));
344 + this.factory = factory;
345 + this.value = value || [];
346 +}
347 +
348 +inherits(SequenceOf, spec.Asn1Spec);
349 +
350 +/**
351 + * @param s {type.Stream}
352 + * @param decoder {ber.decoder}
353 + * @returns {SequenceOf}
354 + */
355 +SequenceOf.prototype.decode = function(s, decoder) {
356 + var sequenceOfStream = new type.Stream(decoder.decode(s, this.tag).value);
357 + while (sequenceOfStream.availableLength() > 0) {
358 + this.value.push(this.factory().decode(sequenceOfStream, decoder));
359 + }
360 + return this;
361 +};
362 +
363 +/**
364 + * BitString type
365 + * @param value {Buffer}
366 + */
367 +function BitString(value) {
368 + spec.Asn1Spec.call(this, new spec.Asn1Tag(spec.TagClass.Universal, spec.TagFormat.Primitive, UniversalTag.BitString));
369 + this.value = [];
370 +}
371 +
372 +inherits(BitString, spec.Asn1Spec);
373 +
374 +/**
375 + * @param s {type.Stream}
376 + * @param decoder {ber.decoder}
377 + * @returns {BitString}
378 + */
379 +BitString.prototype.decode = function(s, decoder) {
380 + var bitStream = new type.Stream(decoder.decode(s, this.tag).value);
381 + var padding = new type.UInt8().read(bitStream).value;
382 + var value = [];
383 + for(var i = 0; i < padding; i++) {
384 + value.push(0);
385 + }
386 +
387 + while(bitStream.availableLength() > 0) {
388 + var octet = new type.UInt8().read(bitStream).value;
389 + var currentPadding = 0;
390 + if(bitStream.availableLength() === 0) {
391 + currentPadding = padding;
392 + }
393 + for(var i = 7; i >= currentPadding; i--) {
394 + value.push(((octet >> i) & 1)?1:0);
395 + }
396 + }
397 + this.value = value;
398 + return this;
399 +};
400 +
401 +/**
402 + * Convert bit string to buffer object
403 + * @returns {Buffer}
404 + */
405 +BitString.prototype.toBuffer = function () {
406 + var length = this.value.length / 8;
407 + var resultStream = new type.Stream(length);
408 + for (var i = 0; i < length; i ++) {
409 + var currentOctet = 0;
410 + for (var j = 0; j < 8; j++) {
411 + currentOctet = currentOctet | (this.value[i * 8 + j] << (7 - j));
412 + }
413 + new type.UInt8(currentOctet).write(resultStream);
414 + }
415 + return resultStream.buffer;
416 +}
417 +
418 +/**
419 + * T61String type
420 + * @param value {Buffer}
421 + */
422 +function T61String(value) {
423 + spec.Asn1Spec.call(this, new spec.Asn1Tag(spec.TagClass.Universal, spec.TagFormat.Primitive, UniversalTag.T61String));
424 + this.value = value;
425 +}
426 +
427 +inherits(T61String, spec.Asn1Spec);
428 +
429 +/**
430 + * @param s {type.Stream}
431 + * @param decoder {ber.decoder}
432 + * @returns {T61String}
433 + */
434 +T61String.prototype.decode = function(s, decoder) {
435 + this.value = decoder.decode(s, this.tag).value;
436 + return this;
437 +};
438 +
439 +/**
440 + * PrintableString type
441 + * @param value {Buffer}
442 + */
443 +function PrintableString(value) {
444 + spec.Asn1Spec.call(this, new spec.Asn1Tag(spec.TagClass.Universal, spec.TagFormat.Primitive, UniversalTag.PrintableString));
445 + this.value = value;
446 +}
447 +
448 +inherits(PrintableString, spec.Asn1Spec);
449 +
450 +/**
451 + * @param s {type.Stream}
452 + * @param decoder {ber.decoder}
453 + * @returns {PrintableString}
454 + */
455 +PrintableString.prototype.decode = function(s, decoder) {
456 + this.value = decoder.decode(s, this.tag).value;
457 + return this;
458 +};
459 +
460 +/**
461 + * UniversalString type
462 + * @param value {Buffer}
463 + */
464 +function UniversalString(value) {
465 + spec.Asn1Spec.call(this, new spec.Asn1Tag(spec.TagClass.Universal, spec.TagFormat.Primitive, UniversalTag.UniversalString));
466 + this.value = value;
467 +}
468 +
469 +inherits(UniversalString, spec.Asn1Spec);
470 +
471 +/**
472 + * @param s {type.Stream}
473 + * @param decoder {ber.decoder}
474 + * @returns {UniversalString}
475 + */
476 +UniversalString.prototype.decode = function(s, decoder) {
477 + this.value = decoder.decode(s, this.tag).value;
478 + return this;
479 +};
480 +
481 +/**
482 + * UTF8String type
483 + * @param value {Buffer}
484 + */
485 +function UTF8String(value) {
486 + spec.Asn1Spec.call(this, new spec.Asn1Tag(spec.TagClass.Universal, spec.TagFormat.Primitive, UniversalTag.UTF8String));
487 + this.value = value;
488 +}
489 +
490 +inherits(UTF8String, spec.Asn1Spec);
491 +
492 +/**
493 + * @param s {type.Stream}
494 + * @param decoder {ber.decoder}
495 + * @returns {UTF8String}
496 + */
497 +UTF8String.prototype.decode = function(s, decoder) {
498 + this.value = decoder.decode(s, this.tag).value;
499 + return this;
500 +};
501 +
502 +/**
503 + * BMPString type
504 + * @param value {Buffer}
505 + */
506 +function BMPString(value) {
507 + spec.Asn1Spec.call(this, new spec.Asn1Tag(spec.TagClass.Universal, spec.TagFormat.Primitive, UniversalTag.BMPString));
508 + this.value = value;
509 +}
510 +
511 +inherits(BMPString, spec.Asn1Spec);
512 +
513 +/**
514 + * @param s {type.Stream}
515 + * @param decoder {ber.decoder}
516 + * @returns {BMPString}
517 + */
518 +BMPString.prototype.decode = function(s, decoder) {
519 + this.value = decoder.decode(s, this.tag).value;
520 + return this;
521 +};
522 +
523 +/**
524 + * IA5String type
525 + * @param value {Buffer}
526 + */
527 +function IA5String(value) {
528 + spec.Asn1Spec.call(this, new spec.Asn1Tag(spec.TagClass.Universal, spec.TagFormat.Primitive, UniversalTag.IA5String));
529 + this.value = value;
530 +}
531 +
532 +inherits(IA5String, spec.Asn1Spec);
533 +
534 +/**
535 + * @param s {type.Stream}
536 + * @param decoder {ber.decoder}
537 + * @returns {IA5String}
538 + */
539 +IA5String.prototype.decode = function(s, decoder) {
540 + this.value = decoder.decode(s, this.tag).value;
541 + return this;
542 +};
543 +
544 +/**
545 + * UTCTime type
546 + * @param value {Buffer}
547 + */
548 +function UTCTime(value) {
549 + spec.Asn1Spec.call(this, new spec.Asn1Tag(spec.TagClass.Universal, spec.TagFormat.Primitive, UniversalTag.UTCTime));
550 + this.value = value;
551 +}
552 +
553 +inherits(UTCTime, spec.Asn1Spec);
554 +
555 +/**
556 + * @param s {type.Stream}
557 + * @param decoder {ber.decoder}
558 + * @returns {UTCTime}
559 + */
560 +UTCTime.prototype.decode = function(s, decoder) {
561 + this.value = decoder.decode(s, this.tag).value;
562 + return this;
563 +};
564 +
565 +/**
566 + * GeneralizedTime type
567 + * @param value {Buffer}
568 + */
569 +function GeneralizedTime(value) {
570 + spec.Asn1Spec.call(this, new spec.Asn1Tag(spec.TagClass.Universal, spec.TagFormat.Primitive, UniversalTag.GeneralizedTime));
571 + this.value = value;
572 +}
573 +
574 +inherits(GeneralizedTime, spec.Asn1Spec);
575 +
576 +/**
577 + * @param s {type.Stream}
578 + * @param decoder {ber.decoder}
579 + * @returns {GeneralizedTime}
580 + */
581 +GeneralizedTime.prototype.decode = function(s, decoder) {
582 + this.value = decoder.decode(s, this.tag).value;
583 + return this;
584 +};
585 +
586 +module.exports = {
587 + Boolean : Boolean,
588 + Integer : Integer,
589 + Sequence : Sequence,
590 + Enumerate : Enumerate,
591 + OctetString : OctetString,
592 + ObjectIdentifier : ObjectIdentifier,
593 + Null : Null,
594 + Choice : Choice,
595 + SequenceOf : SequenceOf,
596 + SetOf : SetOf,
597 + BitString : BitString,
598 + T61String : T61String,
599 + PrintableString : PrintableString,
600 + UniversalString : UniversalString,
601 + UTF8String : UTF8String,
602 + BMPString : BMPString,
603 + IA5String : IA5String,
604 + UTCTime : UTCTime,
605 + GeneralizedTime : GeneralizedTime
606 +};
rdp/core/error.js new
+71
@@ -0,0 +1,71 @@
1 +/*
2 + * Copyright (c) 2014-2015 Sylvain Peyrefitte
3 + *
4 + * This file is part of node-rdpjs.
5 + *
6 + * node-rdpjs is free software: you can redistribute it and/or modify
7 + * it under the terms of the GNU General Public License as published by
8 + * the Free Software Foundation, either version 3 of the License, or
9 + * (at your option) any later version.
10 + *
11 + * This program is distributed in the hope that it will be useful,
12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 + * GNU General Public License for more details.
15 + *
16 + * You should have received a copy of the GNU General Public License
17 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 + */
19 +
20 +var inherits = require('util').inherits;
21 +
22 +/**
23 + * Fatal error stop program
24 + */
25 +function FatalError(message, code) {
26 + Error.captureStackTrace(this);
27 + this.message = message || "";
28 + this.code = code || 'NODE_RDP_CORE_ERROR_NO_ERROR_CODE';
29 +}
30 +
31 +/**
32 + * inherit from error
33 + */
34 +inherits(FatalError, Error);
35 +
36 +/**
37 + * Protocol error (non fatal);
38 + */
39 +function ProtocolError(code, message) {
40 + Error.captureStackTrace(this);
41 + this.code = code;
42 + this.message = message || "";
43 +}
44 +
45 +/**
46 + * inherit from error
47 + */
48 +inherits(ProtocolError, Error);
49 +
50 +/**
51 + * ImplementationError error (non fatal);
52 + */
53 +function ImplementationError(code, message) {
54 + Error.captureStackTrace(this);
55 + this.code = code;
56 + this.message = message || "";
57 +}
58 +
59 +/**
60 + * inherit from error
61 + */
62 +inherits(ImplementationError, Error);
63 +
64 +/**
65 + * Module exports
66 + */
67 +module.exports = {
68 + FatalError : FatalError,
69 + ProtocolError : ProtocolError,
70 + ImplementationError : ImplementationError
71 +};
\ No newline at end of file
rdp/core/index.js new
+32
@@ -0,0 +1,32 @@
1 +/*
2 + * Copyright (c) 2014-2015 Sylvain Peyrefitte
3 + *
4 + * This file is part of node-rdpjs.
5 + *
6 + * node-rdpjs is free software: you can redistribute it and/or modify
7 + * it under the terms of the GNU General Public License as published by
8 + * the Free Software Foundation, either version 3 of the License, or
9 + * (at your option) any later version.
10 + *
11 + * This program is distributed in the hope that it will be useful,
12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 + * GNU General Public License for more details.
15 + *
16 + * You should have received a copy of the GNU General Public License
17 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 + */
19 +
20 +var layer = require('./layer');
21 +var type = require('./type');
22 +var log = require('./log');
23 +var error = require('./error');
24 +var rle = require('./rle');
25 +
26 +module.exports = {
27 + layer : layer,
28 + type : type,
29 + log : log,
30 + error : error,
31 + rle : rle
32 +};
rdp/core/layer.js new
+229
@@ -0,0 +1,229 @@
1 +/*
2 + * Copyright (c) 2014-2015 Sylvain Peyrefitte
3 + *
4 + * This file is part of node-rdpjs.
5 + *
6 + * node-rdpjs is free software: you can redistribute it and/or modify
7 + * it under the terms of the GNU General Public License as published by
8 + * the Free Software Foundation, either version 3 of the License, or
9 + * (at your option) any later version.
10 + *
11 + * This program is distributed in the hope that it will be useful,
12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 + * GNU General Public License for more details.
15 + *
16 + * You should have received a copy of the GNU General Public License
17 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 + */
19 +
20 +var inherits = require('util').inherits;
21 +var fs = require('fs');
22 +var type = require('./type');
23 +var log = require('./log');
24 +var tls = require('tls');
25 +var crypto = require('crypto');
26 +var events = require('events');
27 +
28 +/**
29 + * Buffer data from socket to present
30 + * well formed packets
31 + */
32 +function BufferLayer(socket) {
33 + //for ssl connection
34 + this.secureSocket = null;
35 + this.socket = socket;
36 +
37 + var self = this;
38 + // bind event
39 + this.socket.on('data', function(data) {
40 + try {
41 + self.recv(data);
42 + }
43 + catch(e) {
44 + self.socket.destroy();
45 + self.emit('error', e);
46 + }
47 + }).on('close', function() {
48 + self.emit('close');
49 + }).on('error', function (err) {
50 + self.emit('error', err);
51 + });
52 +
53 + //buffer data
54 + this.buffers = [];
55 + this.bufferLength = 0;
56 + //expected size
57 + this.expectedSize = 0;
58 +}
59 +
60 +inherits(BufferLayer, events.EventEmitter);
61 +
62 +/**
63 + * Call from tcp layer
64 + * @param data tcp stream
65 + */
66 +BufferLayer.prototype.recv = function (data) {
67 + if (this.buffers.length == 0) { this.bufferLength = 0; } // CORRECT
68 + this.buffers[this.buffers.length] = data;
69 + this.bufferLength += data.length;
70 +
71 + //console.log('TCP RECV', this.bufferLength, this.expectedSize, data.toString('hex'));
72 + //console.log('this.buffers', this.buffers);
73 + //console.log('this.expectedSize', this.expectedSize);
74 + //console.log('this.bufferLength', this.bufferLength);
75 +
76 + if (this.expectedSize == 0) { console.log('this.expectedSize == 0'); return; }
77 +
78 + while (this.bufferLength >= this.expectedSize) {
79 + //console.log('this.expectedSize', this.expectedSize);
80 + //console.log('this.bufferLength', this.bufferLength);
81 +
82 + //linear buffer
83 + var expectedData = new type.Stream(this.expectedSize);
84 +
85 + //create expected data
86 + while (expectedData.availableLength() > 0) {
87 +
88 + var rest = expectedData.availableLength();
89 + var buffer = this.buffers.shift();
90 +
91 + //console.log('xx', rest, buffer);
92 +
93 + if (buffer.length > expectedData.availableLength()) {
94 + this.buffers.unshift(buffer.slice(rest));
95 + new type.BinaryString(buffer, { readLength : new type.CallableValue(expectedData.availableLength()) }).write(expectedData);
96 + } else {
97 + new type.BinaryString(buffer).write(expectedData);
98 + }
99 + }
100 +
101 + this.bufferLength -= this.expectedSize;
102 + expectedData.offset = 0;
103 +
104 + //console.log('TCP EMIT', expectedData);
105 + this.emit('data', expectedData);
106 + }
107 +};
108 +
109 +/**
110 + * Call tcp socket to write stream
111 + * @param {type.Type} packet
112 + */
113 +BufferLayer.prototype.send = function(data) {
114 + var s = new type.Stream(data.size());
115 + data.write(s);
116 + if(this.secureSocket) {
117 + this.secureSocket.write(s.buffer);
118 + }
119 + else {
120 + this.socket.write(s.buffer);
121 + }
122 +};
123 +
124 +/**
125 + * Call tcp socket to write a buffer
126 + */
127 +BufferLayer.prototype.sendBuffer = function (buffer) {
128 + if (this.secureSocket) {
129 + //console.log('SSL sendBuffer', buffer.length, buffer.toString('hex'));
130 + this.secureSocket.write(buffer);
131 + }
132 + else {
133 + //console.log('TCP sendBuffer', buffer.length, buffer.toString('hex'));
134 + this.socket.write(buffer);
135 + }
136 +};
137 +
138 +/**
139 + * Wait expected size data before call callback function
140 + * @param {number} expectSize size expected
141 + */
142 +BufferLayer.prototype.expect = function(expectedSize) {
143 + this.expectedSize = expectedSize;
144 +};
145 +
146 +/**
147 + * Convert connection to TLS connection
148 + * @param callback {func} when connection is done
149 + */
150 +BufferLayer.prototype.startTLS = function(callback) {
151 + var self = this;
152 +
153 + this.secureSocket = tls.connect({
154 + socket: this.socket,
155 + secureContext: tls.createSecureContext(),
156 + isServer: false,
157 + requestCert: false,
158 + rejectUnauthorized: false
159 + }, (err) => {
160 + log.warn(err);
161 + callback(err);
162 + });
163 +
164 + this.secureSocket.on('data', function (data) {
165 +
166 + //console.log('SSL RECV', data.length, data);
167 +
168 + try {
169 + self.recv(data);
170 + }
171 + catch (e) {
172 + //console.log('SSL RECV ERR', e);
173 + self.socket.destroy();
174 + self.emit('error', e);
175 + }
176 + }).on('error', function (err) {
177 + self.emit('error', err);
178 + });
179 +};
180 +
181 +/**
182 + * Convert connection to TLS server
183 + * @param keyFilePath {string} key file path
184 + * @param crtFilePath {string} certificat file path
185 + * @param callback {function}
186 + */
187 +BufferLayer.prototype.listenTLS = function(keyFilePath, crtFilePath, callback) {
188 + var self = this;
189 +
190 + this.secureSocket = tls.connect({
191 + socket: this.socket,
192 + secureContext: tls.createSecureContext({
193 + key: fs.readFileSync(keyFilePath),
194 + cert: fs.readFileSync(crtFilePath),
195 + }),
196 + isServer: true,
197 + requestCert: false,
198 + rejectUnauthorized: false
199 + }, (err) => {
200 + log.warn(err);
201 + callback(err);
202 + });
203 +
204 + this.secureSocket.on('data', function(data) {
205 + try {
206 + self.recv(data);
207 + }
208 + catch(e) {
209 + self.socket.destroy();
210 + self.emit('error', e);
211 + }
212 + }).on('error', function (err) {
213 + self.emit('error', err);
214 + });
215 +};
216 +
217 +/**
218 + * close stack
219 + */
220 +BufferLayer.prototype.close = function() {
221 + this.socket.end();
222 +};
223 +
224 +/**
225 + * Module exports
226 + */
227 +module.exports = {
228 + BufferLayer : BufferLayer
229 +};
rdp/core/log.js new
+81
@@ -0,0 +1,81 @@
1 +/*
2 + * Copyright (c) 2014-2015 Sylvain Peyrefitte
3 + *
4 + * This file is part of node-rdpjs.
5 + *
6 + * node-rdpjs is free software: you can redistribute it and/or modify
7 + * it under the terms of the GNU General Public License as published by
8 + * the Free Software Foundation, either version 3 of the License, or
9 + * (at your option) any later version.
10 + *
11 + * This program is distributed in the hope that it will be useful,
12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 + * GNU General Public License for more details.
15 + *
16 + * You should have received a copy of the GNU General Public License
17 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 + */
19 +
20 +var Levels = {
21 + 'DEBUG': 1,
22 + 'INFO': 2,
23 + 'WARN': 3,
24 + 'ERROR': 4,
25 + 'NONE': 5
26 +}
27 +
28 +/*
29 +var Logger = require('bunyan');
30 +
31 +let logStreams = [];
32 +
33 +if (process.env.enable_log_file === 'true') {
34 + logStreams.push(
35 + {
36 + type: 'rotating-file',
37 + period: '1d',
38 + count: 2,
39 + path: `node-rdpjs${process.pid}.log`,
40 + level: process.env.log_level
41 + }
42 + );
43 +}
44 +
45 +logStreams.push(
46 + {
47 + stream: process.stderr,
48 + level: process.env.log_level
49 + }
50 +);
51 +
52 +var logger = Logger.createLogger({
53 + name: 'node-rdpjs',
54 + streams: logStreams
55 +});
56 +*/
57 +
58 +function log(level, message) {
59 + if (Levels[level] < module.exports.level) return;
60 + console.log("[node-rdpjs] " + level + ":\t" + message);
61 +}
62 +
63 +/**
64 + * Module exports
65 + */
66 +module.exports = {
67 + level: Levels.INFO, // Levels.INFO,
68 + Levels: Levels,
69 + debug: function (message) {
70 + //logger.debug(message);
71 + },
72 + info: function (message) {
73 + //logger.info(message);
74 + },
75 + warn: function (message) {
76 + //logger.warn(message);
77 + },
78 + error: function (message) {
79 + //logger.error(message);
80 + }
81 +};
rdp/core/rle.js new
+17868
@@ -0,0 +1,17868 @@
1 +// Note: Some Emscripten settings will significantly limit the speed of the generated code.
2 +// Note: Some Emscripten settings may limit the speed of the generated code.
3 +// The Module object: Our interface to the outside world. We import
4 +// and export values on it, and do the work to get that through
5 +// closure compiler if necessary. There are various ways Module can be used:
6 +// 1. Not defined. We create it here
7 +// 2. A function parameter, function(Module) { ..generated code.. }
8 +// 3. pre-run appended it, var Module = {}; ..generated code..
9 +// 4. External script tag defines var Module.
10 +// We need to do an eval in order to handle the closure compiler
11 +// case, where this code here is minified but Module was defined
12 +// elsewhere (e.g. case 4 above). We also need to check if Module
13 +// already exists (e.g. case 3 above).
14 +// Note that if you want to run closure, and also to use Module
15 +// after the generated code, you will need to define var Module = {};
16 +// before the code. Then that object will be used in the code, and you
17 +// can continue to use Module afterwards as well.
18 +var Module;
19 +if (!Module) Module = eval('(function() { try { return Module || {} } catch(e) { return {} } })()');
20 +
21 +// Sometimes an existing Module object exists with properties
22 +// meant to overwrite the default module functionality. Here
23 +// we collect those properties and reapply _after_ we configure
24 +// the current environment's defaults to avoid having to be so
25 +// defensive during initialization.
26 +var moduleOverrides = {};
27 +for (var key in Module) {
28 + if (Module.hasOwnProperty(key)) {
29 + moduleOverrides[key] = Module[key];
30 + }
31 +}
32 +
33 +// The environment setup code below is customized to use Module.
34 +// *** Environment setup code ***
35 +var ENVIRONMENT_IS_NODE = typeof process === 'object' && typeof require === 'function';
36 +var ENVIRONMENT_IS_WEB = typeof window === 'object';
37 +var ENVIRONMENT_IS_WORKER = typeof importScripts === 'function';
38 +var ENVIRONMENT_IS_SHELL = !ENVIRONMENT_IS_WEB && !ENVIRONMENT_IS_NODE && !ENVIRONMENT_IS_WORKER;
39 +
40 +if (ENVIRONMENT_IS_NODE) {
41 + // Expose functionality in the same simple way that the shells work
42 + // Note that we pollute the global namespace here, otherwise we break in node
43 + if (!Module['print']) Module['print'] = function print(x) {
44 + process['stdout'].write(x + '\n');
45 + };
46 + if (!Module['printErr']) Module['printErr'] = function printErr(x) {
47 + process['stderr'].write(x + '\n');
48 + };
49 +
50 + var nodeFS = require('fs');
51 + var nodePath = require('path');
52 +
53 + Module['read'] = function read(filename, binary) {
54 + filename = nodePath['normalize'](filename);
55 + var ret = nodeFS['readFileSync'](filename);
56 + // The path is absolute if the normalized version is the same as the resolved.
57 + if (!ret && filename != nodePath['resolve'](filename)) {
58 + filename = path.join(__dirname, '..', 'src', filename);
59 + ret = nodeFS['readFileSync'](filename);
60 + }
61 + if (ret && !binary) ret = ret.toString();
62 + return ret;
63 + };
64 +
65 + Module['readBinary'] = function readBinary(filename) { return Module['read'](filename, true) };
66 +
67 + Module['load'] = function load(f) {
68 + globalEval(read(f));
69 + };
70 +
71 + Module['arguments'] = process['argv'].slice(2);
72 +
73 + module['exports'] = Module;
74 +}
75 +else if (ENVIRONMENT_IS_SHELL) {
76 + if (!Module['print']) Module['print'] = print;
77 + if (typeof printErr != 'undefined') Module['printErr'] = printErr; // not present in v8 or older sm
78 +
79 + if (typeof read != 'undefined') {
80 + Module['read'] = read;
81 + } else {
82 + Module['read'] = function read() { throw 'no read() available (jsc?)' };
83 + }
84 +
85 + Module['readBinary'] = function readBinary(f) {
86 + return read(f, 'binary');
87 + };
88 +
89 + if (typeof scriptArgs != 'undefined') {
90 + Module['arguments'] = scriptArgs;
91 + } else if (typeof arguments != 'undefined') {
92 + Module['arguments'] = arguments;
93 + }
94 +
95 + this['Module'] = Module;
96 +
97 + eval("if (typeof gc === 'function' && gc.toString().indexOf('[native code]') > 0) var gc = undefined"); // wipe out the SpiderMonkey shell 'gc' function, which can confuse closure (uses it as a minified name, and it is then initted to a non-falsey value unexpectedly)
98 +}
99 +else if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) {
100 + Module['read'] = function read(url) {
101 + var xhr = new XMLHttpRequest();
102 + xhr.open('GET', url, false);
103 + xhr.send(null);
104 + return xhr.responseText;
105 + };
106 +
107 + if (typeof arguments != 'undefined') {
108 + Module['arguments'] = arguments;
109 + }
110 +
111 + if (typeof console !== 'undefined') {
112 + if (!Module['print']) Module['print'] = function print(x) {
113 + console.log(x);
114 + };
115 + if (!Module['printErr']) Module['printErr'] = function printErr(x) {
116 + console.log(x);
117 + };
118 + } else {
119 + // Probably a worker, and without console.log. We can do very little here...
120 + var TRY_USE_DUMP = false;
121 + if (!Module['print']) Module['print'] = (TRY_USE_DUMP && (typeof(dump) !== "undefined") ? (function(x) {
122 + dump(x);
123 + }) : (function(x) {
124 + // self.postMessage(x); // enable this if you want stdout to be sent as messages
125 + }));
126 + }
127 +
128 + if (ENVIRONMENT_IS_WEB) {
129 + this['Module'] = Module;
130 + } else {
131 + Module['load'] = importScripts;
132 + }
133 +}
134 +else {
135 + // Unreachable because SHELL is dependant on the others
136 + throw 'Unknown runtime environment. Where are we?';
137 +}
138 +
139 +function globalEval(x) {
140 + eval.call(null, x);
141 +}
142 +if (!Module['load'] == 'undefined' && Module['read']) {
143 + Module['load'] = function load(f) {
144 + globalEval(Module['read'](f));
145 + };
146 +}
147 +if (!Module['print']) {
148 + Module['print'] = function(){};
149 +}
150 +if (!Module['printErr']) {
151 + Module['printErr'] = Module['print'];
152 +}
153 +if (!Module['arguments']) {
154 + Module['arguments'] = [];
155 +}
156 +// *** Environment setup code ***
157 +
158 +// Closure helpers
159 +Module.print = Module['print'];
160 +Module.printErr = Module['printErr'];
161 +
162 +// Callbacks
163 +Module['preRun'] = [];
164 +Module['postRun'] = [];
165 +
166 +// Merge back in the overrides
167 +for (var key in moduleOverrides) {
168 + if (moduleOverrides.hasOwnProperty(key)) {
169 + Module[key] = moduleOverrides[key];
170 + }
171 +}
172 +
173 +
174 +
175 +// === Auto-generated preamble library stuff ===
176 +
177 +//========================================
178 +// Runtime code shared with compiler
179 +//========================================
180 +
181 +var Runtime = {
182 + stackSave: function () {
183 + return STACKTOP;
184 + },
185 + stackRestore: function (stackTop) {
186 + STACKTOP = stackTop;
187 + },
188 + forceAlign: function (target, quantum) {
189 + quantum = quantum || 4;
190 + if (quantum == 1) return target;
191 + if (isNumber(target) && isNumber(quantum)) {
192 + return Math.ceil(target/quantum)*quantum;
193 + } else if (isNumber(quantum) && isPowerOfTwo(quantum)) {
194 + return '(((' +target + ')+' + (quantum-1) + ')&' + -quantum + ')';
195 + }
196 + return 'Math.ceil((' + target + ')/' + quantum + ')*' + quantum;
197 + },
198 + isNumberType: function (type) {
199 + return type in Runtime.INT_TYPES || type in Runtime.FLOAT_TYPES;
200 + },
201 + isPointerType: function isPointerType(type) {
202 + return type[type.length-1] == '*';
203 +},
204 + isStructType: function isStructType(type) {
205 + if (isPointerType(type)) return false;
206 + if (isArrayType(type)) return true;
207 + if (/<?{ ?[^}]* ?}>?/.test(type)) return true; // { i32, i8 } etc. - anonymous struct types
208 + // See comment in isStructPointerType()
209 + return type[0] == '%';
210 +},
211 + INT_TYPES: {"i1":0,"i8":0,"i16":0,"i32":0,"i64":0},
212 + FLOAT_TYPES: {"float":0,"double":0},
213 + or64: function (x, y) {
214 + var l = (x | 0) | (y | 0);
215 + var h = (Math.round(x / 4294967296) | Math.round(y / 4294967296)) * 4294967296;
216 + return l + h;
217 + },
218 + and64: function (x, y) {
219 + var l = (x | 0) & (y | 0);
220 + var h = (Math.round(x / 4294967296) & Math.round(y / 4294967296)) * 4294967296;
221 + return l + h;
222 + },
223 + xor64: function (x, y) {
224 + var l = (x | 0) ^ (y | 0);
225 + var h = (Math.round(x / 4294967296) ^ Math.round(y / 4294967296)) * 4294967296;
226 + return l + h;
227 + },
228 + getNativeTypeSize: function (type) {
229 + switch (type) {
230 + case 'i1': case 'i8': return 1;
231 + case 'i16': return 2;
232 + case 'i32': return 4;
233 + case 'i64': return 8;
234 + case 'float': return 4;
235 + case 'double': return 8;
236 + default: {
237 + if (type[type.length-1] === '*') {
238 + return Runtime.QUANTUM_SIZE; // A pointer
239 + } else if (type[0] === 'i') {
240 + var bits = parseInt(type.substr(1));
241 + assert(bits % 8 === 0);
242 + return bits/8;
243 + } else {
244 + return 0;
245 + }
246 + }
247 + }
248 + },
249 + getNativeFieldSize: function (type) {
250 + return Math.max(Runtime.getNativeTypeSize(type), Runtime.QUANTUM_SIZE);
251 + },
252 + dedup: function dedup(items, ident) {
253 + var seen = {};
254 + if (ident) {
255 + return items.filter(function(item) {
256 + if (seen[item[ident]]) return false;
257 + seen[item[ident]] = true;
258 + return true;
259 + });
260 + } else {
261 + return items.filter(function(item) {
262 + if (seen[item]) return false;
263 + seen[item] = true;
264 + return true;
265 + });
266 + }
267 +},
268 + set: function set() {
269 + var args = typeof arguments[0] === 'object' ? arguments[0] : arguments;
270 + var ret = {};
271 + for (var i = 0; i < args.length; i++) {
272 + ret[args[i]] = 0;
273 + }
274 + return ret;
275 +},
276 + STACK_ALIGN: 8,
277 + getAlignSize: function (type, size, vararg) {
278 + // we align i64s and doubles on 64-bit boundaries, unlike x86
279 + if (vararg) return 8;
280 + if (!vararg && (type == 'i64' || type == 'double')) return 8;
281 + if (!type) return Math.min(size, 8); // align structures internally to 64 bits
282 + return Math.min(size || (type ? Runtime.getNativeFieldSize(type) : 0), Runtime.QUANTUM_SIZE);
283 + },
284 + calculateStructAlignment: function calculateStructAlignment(type) {
285 + type.flatSize = 0;
286 + type.alignSize = 0;
287 + var diffs = [];
288 + var prev = -1;
289 + var index = 0;
290 + type.flatIndexes = type.fields.map(function(field) {
291 + index++;
292 + var size, alignSize;
293 + if (Runtime.isNumberType(field) || Runtime.isPointerType(field)) {
294 + size = Runtime.getNativeTypeSize(field); // pack char; char; in structs, also char[X]s.
295 + alignSize = Runtime.getAlignSize(field, size);
296 + } else if (Runtime.isStructType(field)) {
297 + if (field[1] === '0') {
298 + // this is [0 x something]. When inside another structure like here, it must be at the end,
299 + // and it adds no size
300 + // XXX this happens in java-nbody for example... assert(index === type.fields.length, 'zero-length in the middle!');
301 + size = 0;
302 + if (Types.types[field]) {
303 + alignSize = Runtime.getAlignSize(null, Types.types[field].alignSize);
304 + } else {
305 + alignSize = type.alignSize || QUANTUM_SIZE;
306 + }
307 + } else {
308 + size = Types.types[field].flatSize;
309 + alignSize = Runtime.getAlignSize(null, Types.types[field].alignSize);
310 + }
311 + } else if (field[0] == 'b') {
312 + // bN, large number field, like a [N x i8]
313 + size = field.substr(1)|0;
314 + alignSize = 1;
315 + } else if (field[0] === '<') {
316 + // vector type
317 + size = alignSize = Types.types[field].flatSize; // fully aligned
318 + } else if (field[0] === 'i') {
319 + // illegal integer field, that could not be legalized because it is an internal structure field
320 + // it is ok to have such fields, if we just use them as markers of field size and nothing more complex
321 + size = alignSize = parseInt(field.substr(1))/8;
322 + assert(size % 1 === 0, 'cannot handle non-byte-size field ' + field);
323 + } else {
324 + assert(false, 'invalid type for calculateStructAlignment');
325 + }
326 + if (type.packed) alignSize = 1;
327 + type.alignSize = Math.max(type.alignSize, alignSize);
328 + var curr = Runtime.alignMemory(type.flatSize, alignSize); // if necessary, place this on aligned memory
329 + type.flatSize = curr + size;
330 + if (prev >= 0) {
331 + diffs.push(curr-prev);
332 + }
333 + prev = curr;
334 + return curr;
335 + });
336 + if (type.name_ && type.name_[0] === '[') {
337 + // arrays have 2 elements, so we get the proper difference. then we scale here. that way we avoid
338 + // allocating a potentially huge array for [999999 x i8] etc.
339 + type.flatSize = parseInt(type.name_.substr(1))*type.flatSize/2;
340 + }
341 + type.flatSize = Runtime.alignMemory(type.flatSize, type.alignSize);
342 + if (diffs.length == 0) {
343 + type.flatFactor = type.flatSize;
344 + } else if (Runtime.dedup(diffs).length == 1) {
345 + type.flatFactor = diffs[0];
346 + }
347 + type.needsFlattening = (type.flatFactor != 1);
348 + return type.flatIndexes;
349 + },
350 + generateStructInfo: function (struct, typeName, offset) {
351 + var type, alignment;
352 + if (typeName) {
353 + offset = offset || 0;
354 + type = (typeof Types === 'undefined' ? Runtime.typeInfo : Types.types)[typeName];
355 + if (!type) return null;
356 + if (type.fields.length != struct.length) {
357 + printErr('Number of named fields must match the type for ' + typeName + ': possibly duplicate struct names. Cannot return structInfo');
358 + return null;
359 + }
360 + alignment = type.flatIndexes;
361 + } else {
362 + var type = { fields: struct.map(function(item) { return item[0] }) };
363 + alignment = Runtime.calculateStructAlignment(type);
364 + }
365 + var ret = {
366 + __size__: type.flatSize
367 + };
368 + if (typeName) {
369 + struct.forEach(function(item, i) {
370 + if (typeof item === 'string') {
371 + ret[item] = alignment[i] + offset;
372 + } else {
373 + // embedded struct
374 + var key;
375 + for (var k in item) key = k;
376 + ret[key] = Runtime.generateStructInfo(item[key], type.fields[i], alignment[i]);
377 + }
378 + });
379 + } else {
380 + struct.forEach(function(item, i) {
381 + ret[item[1]] = alignment[i];
382 + });
383 + }
384 + return ret;
385 + },
386 + dynCall: function (sig, ptr, args) {
387 + if (args && args.length) {
388 + assert(args.length == sig.length-1);
389 + return FUNCTION_TABLE[ptr].apply(null, args);
390 + } else {
391 + assert(sig.length == 1);
392 + return FUNCTION_TABLE[ptr]();
393 + }
394 + },
395 + addFunction: function (func) {
396 + var table = FUNCTION_TABLE;
397 + var ret = table.length;
398 + assert(ret % 2 === 0);
399 + table.push(func);
400 + for (var i = 0; i < 2-1; i++) table.push(0);
401 + return ret;
402 + },
403 + removeFunction: function (index) {
404 + var table = FUNCTION_TABLE;
405 + table[index] = null;
406 + },
407 + getAsmConst: function (code, numArgs) {
408 + // code is a constant string on the heap, so we can cache these
409 + if (!Runtime.asmConstCache) Runtime.asmConstCache = {};
410 + var func = Runtime.asmConstCache[code];
411 + if (func) return func;
412 + var args = [];
413 + for (var i = 0; i < numArgs; i++) {
414 + args.push(String.fromCharCode(36) + i); // $0, $1 etc
415 + }
416 + code = Pointer_stringify(code);
417 + if (code[0] === '"') {
418 + // tolerate EM_ASM("..code..") even though EM_ASM(..code..) is correct
419 + if (code.indexOf('"', 1) === code.length-1) {
420 + code = code.substr(1, code.length-2);
421 + } else {
422 + // something invalid happened, e.g. EM_ASM("..code($0)..", input)
423 + abort('invalid EM_ASM input |' + code + '|. Please use EM_ASM(..code..) (no quotes) or EM_ASM({ ..code($0).. }, input) (to input values)');
424 + }
425 + }
426 + return Runtime.asmConstCache[code] = eval('(function(' + args.join(',') + '){ ' + code + ' })'); // new Function does not allow upvars in node
427 + },
428 + warnOnce: function (text) {
429 + if (!Runtime.warnOnce.shown) Runtime.warnOnce.shown = {};
430 + if (!Runtime.warnOnce.shown[text]) {
431 + Runtime.warnOnce.shown[text] = 1;
432 + Module.printErr(text);
433 + }
434 + },
435 + funcWrappers: {},
436 + getFuncWrapper: function (func, sig) {
437 + assert(sig);
438 + if (!Runtime.funcWrappers[func]) {
439 + Runtime.funcWrappers[func] = function dynCall_wrapper() {
440 + return Runtime.dynCall(sig, func, arguments);
441 + };
442 + }
443 + return Runtime.funcWrappers[func];
444 + },
445 + UTF8Processor: function () {
446 + var buffer = [];
447 + var needed = 0;
448 + this.processCChar = function (code) {
449 + code = code & 0xFF;
450 +
451 + if (buffer.length == 0) {
452 + if ((code & 0x80) == 0x00) { // 0xxxxxxx
453 + return String.fromCharCode(code);
454 + }
455 + buffer.push(code);
456 + if ((code & 0xE0) == 0xC0) { // 110xxxxx
457 + needed = 1;
458 + } else if ((code & 0xF0) == 0xE0) { // 1110xxxx
459 + needed = 2;
460 + } else { // 11110xxx
461 + needed = 3;
462 + }
463 + return '';
464 + }
465 +
466 + if (needed) {
467 + buffer.push(code);
468 + needed--;
469 + if (needed > 0) return '';
470 + }
471 +
472 + var c1 = buffer[0];
473 + var c2 = buffer[1];
474 + var c3 = buffer[2];
475 + var c4 = buffer[3];
476 + var ret;
477 + if (buffer.length == 2) {
478 + ret = String.fromCharCode(((c1 & 0x1F) << 6) | (c2 & 0x3F));
479 + } else if (buffer.length == 3) {
480 + ret = String.fromCharCode(((c1 & 0x0F) << 12) | ((c2 & 0x3F) << 6) | (c3 & 0x3F));
481 + } else {
482 + // http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
483 + var codePoint = ((c1 & 0x07) << 18) | ((c2 & 0x3F) << 12) |
484 + ((c3 & 0x3F) << 6) | (c4 & 0x3F);
485 + ret = String.fromCharCode(
486 + Math.floor((codePoint - 0x10000) / 0x400) + 0xD800,
487 + (codePoint - 0x10000) % 0x400 + 0xDC00);
488 + }
489 + buffer.length = 0;
490 + return ret;
491 + }
492 + this.processJSString = function processJSString(string) {
493 + string = unescape(encodeURIComponent(string));
494 + var ret = [];
495 + for (var i = 0; i < string.length; i++) {
496 + ret.push(string.charCodeAt(i));
497 + }
498 + return ret;
499 + }
500 + },
501 + stackAlloc: function (size) { var ret = STACKTOP;STACKTOP = (STACKTOP + size)|0;STACKTOP = (((STACKTOP)+7)&-8);(assert((STACKTOP|0) < (STACK_MAX|0))|0); return ret; },
502 + staticAlloc: function (size) { var ret = STATICTOP;STATICTOP = (STATICTOP + (assert(!staticSealed),size))|0;STATICTOP = (((STATICTOP)+7)&-8); return ret; },
503 + dynamicAlloc: function (size) { var ret = DYNAMICTOP;DYNAMICTOP = (DYNAMICTOP + (assert(DYNAMICTOP > 0),size))|0;DYNAMICTOP = (((DYNAMICTOP)+7)&-8); if (DYNAMICTOP >= TOTAL_MEMORY) enlargeMemory();; return ret; },
504 + alignMemory: function (size,quantum) { var ret = size = Math.ceil((size)/(quantum ? quantum : 8))*(quantum ? quantum : 8); return ret; },
505 + makeBigInt: function (low,high,unsigned) { var ret = (unsigned ? ((low>>>0)+((high>>>0)*4294967296)) : ((low>>>0)+((high|0)*4294967296))); return ret; },
506 + GLOBAL_BASE: 8,
507 + QUANTUM_SIZE: 4,
508 + __dummy__: 0
509 +}
510 +
511 +
512 +Module['Runtime'] = Runtime;
513 +
514 +
515 +
516 +
517 +
518 +
519 +
520 +
521 +
522 +//========================================
523 +// Runtime essentials
524 +//========================================
525 +
526 +var __THREW__ = 0; // Used in checking for thrown exceptions.
527 +var setjmpId = 1; // Used in setjmp/longjmp
528 +var setjmpLabels = {};
529 +
530 +var ABORT = false; // whether we are quitting the application. no code should run after this. set in exit() and abort()
531 +var EXITSTATUS = 0;
532 +
533 +var undef = 0;
534 +// tempInt is used for 32-bit signed values or smaller. tempBigInt is used
535 +// for 32-bit unsigned values or more than 32 bits. TODO: audit all uses of tempInt
536 +var tempValue, tempInt, tempBigInt, tempInt2, tempBigInt2, tempPair, tempBigIntI, tempBigIntR, tempBigIntS, tempBigIntP, tempBigIntD, tempDouble, tempFloat;
537 +var tempI64, tempI64b;
538 +var tempRet0, tempRet1, tempRet2, tempRet3, tempRet4, tempRet5, tempRet6, tempRet7, tempRet8, tempRet9;
539 +
540 +function assert(condition, text) {
541 + if (!condition) {
542 + abort('Assertion failed: ' + text);
543 + }
544 +}
545 +
546 +var globalScope = this;
547 +
548 +// C calling interface. A convenient way to call C functions (in C files, or
549 +// defined with extern "C").
550 +//
551 +// Note: LLVM optimizations can inline and remove functions, after which you will not be
552 +// able to call them. Closure can also do so. To avoid that, add your function to
553 +// the exports using something like
554 +//
555 +// -s EXPORTED_FUNCTIONS='["_main", "_myfunc"]'
556 +//
557 +// @param ident The name of the C function (note that C++ functions will be name-mangled - use extern "C")
558 +// @param returnType The return type of the function, one of the JS types 'number', 'string' or 'array' (use 'number' for any C pointer, and
559 +// 'array' for JavaScript arrays and typed arrays; note that arrays are 8-bit).
560 +// @param argTypes An array of the types of arguments for the function (if there are no arguments, this can be ommitted). Types are as in returnType,
561 +// except that 'array' is not possible (there is no way for us to know the length of the array)
562 +// @param args An array of the arguments to the function, as native JS values (as in returnType)
563 +// Note that string arguments will be stored on the stack (the JS string will become a C string on the stack).
564 +// @return The return value, as a native JS value (as in returnType)
565 +function ccall(ident, returnType, argTypes, args) {
566 + return ccallFunc(getCFunc(ident), returnType, argTypes, args);
567 +}
568 +Module["ccall"] = ccall;
569 +
570 +// Returns the C function with a specified identifier (for C++, you need to do manual name mangling)
571 +function getCFunc(ident) {
572 + try {
573 + var func = Module['_' + ident]; // closure exported function
574 + if (!func) func = eval('_' + ident); // explicit lookup
575 + } catch(e) {
576 + }
577 + assert(func, 'Cannot call unknown function ' + ident + ' (perhaps LLVM optimizations or closure removed it?)');
578 + return func;
579 +}
580 +
581 +// Internal function that does a C call using a function, not an identifier
582 +function ccallFunc(func, returnType, argTypes, args) {
583 + var stack = 0;
584 + function toC(value, type) {
585 + if (type == 'string') {
586 + if (value === null || value === undefined || value === 0) return 0; // null string
587 + value = intArrayFromString(value);
588 + type = 'array';
589 + }
590 + if (type == 'array') {
591 + if (!stack) stack = Runtime.stackSave();
592 + var ret = Runtime.stackAlloc(value.length);
593 + writeArrayToMemory(value, ret);
594 + return ret;
595 + }
596 + return value;
597 + }
598 + function fromC(value, type) {
599 + if (type == 'string') {
600 + return Pointer_stringify(value);
601 + }
602 + assert(type != 'array');
603 + return value;
604 + }
605 + var i = 0;
606 + var cArgs = args ? args.map(function(arg) {
607 + return toC(arg, argTypes[i++]);
608 + }) : [];
609 + var ret = fromC(func.apply(null, cArgs), returnType);
610 + if (stack) Runtime.stackRestore(stack);
611 + return ret;
612 +}
613 +
614 +// Returns a native JS wrapper for a C function. This is similar to ccall, but
615 +// returns a function you can call repeatedly in a normal way. For example:
616 +//
617 +// var my_function = cwrap('my_c_function', 'number', ['number', 'number']);
618 +// alert(my_function(5, 22));
619 +// alert(my_function(99, 12));
620 +//
621 +function cwrap(ident, returnType, argTypes) {
622 + var func = getCFunc(ident);
623 + return function() {
624 + return ccallFunc(func, returnType, argTypes, Array.prototype.slice.call(arguments));
625 + }
626 +}
627 +Module["cwrap"] = cwrap;
628 +
629 +// Sets a value in memory in a dynamic way at run-time. Uses the
630 +// type data. This is the same as makeSetValue, except that
631 +// makeSetValue is done at compile-time and generates the needed
632 +// code then, whereas this function picks the right code at
633 +// run-time.
634 +// Note that setValue and getValue only do *aligned* writes and reads!
635 +// Note that ccall uses JS types as for defining types, while setValue and
636 +// getValue need LLVM types ('i8', 'i32') - this is a lower-level operation
637 +function setValue(ptr, value, type, noSafe) {
638 + type = type || 'i8';
639 + if (type.charAt(type.length-1) === '*') type = 'i32'; // pointers are 32-bit
640 + switch(type) {
641 + case 'i1': HEAP8[(ptr)]=value; break;
642 + case 'i8': HEAP8[(ptr)]=value; break;
643 + case 'i16': HEAP16[((ptr)>>1)]=value; break;
644 + case 'i32': HEAP32[((ptr)>>2)]=value; break;
645 + case 'i64': (tempI64 = [value>>>0,(tempDouble=value,Math_abs(tempDouble) >= 1 ? (tempDouble > 0 ? Math_min(Math_floor((tempDouble)/4294967296), 4294967295)>>>0 : (~~(Math_ceil((tempDouble - +(((~~(tempDouble)))>>>0))/4294967296)))>>>0) : 0)],HEAP32[((ptr)>>2)]=tempI64[0],HEAP32[(((ptr)+(4))>>2)]=tempI64[1]); break;
646 + case 'float': HEAPF32[((ptr)>>2)]=value; break;
647 + case 'double': HEAPF64[((ptr)>>3)]=value; break;
648 + default: abort('invalid type for setValue: ' + type);
649 + }
650 +}
651 +Module['setValue'] = setValue;
652 +
653 +// Parallel to setValue.
654 +function getValue(ptr, type, noSafe) {
655 + type = type || 'i8';
656 + if (type.charAt(type.length-1) === '*') type = 'i32'; // pointers are 32-bit
657 + switch(type) {
658 + case 'i1': return HEAP8[(ptr)];
659 + case 'i8': return HEAP8[(ptr)];
660 + case 'i16': return HEAP16[((ptr)>>1)];
661 + case 'i32': return HEAP32[((ptr)>>2)];
662 + case 'i64': return HEAP32[((ptr)>>2)];
663 + case 'float': return HEAPF32[((ptr)>>2)];
664 + case 'double': return HEAPF64[((ptr)>>3)];
665 + default: abort('invalid type for setValue: ' + type);
666 + }
667 + return null;
668 +}
669 +Module['getValue'] = getValue;
670 +
671 +var ALLOC_NORMAL = 0; // Tries to use _malloc()
672 +var ALLOC_STACK = 1; // Lives for the duration of the current function call
673 +var ALLOC_STATIC = 2; // Cannot be freed
674 +var ALLOC_DYNAMIC = 3; // Cannot be freed except through sbrk
675 +var ALLOC_NONE = 4; // Do not allocate
676 +Module['ALLOC_NORMAL'] = ALLOC_NORMAL;
677 +Module['ALLOC_STACK'] = ALLOC_STACK;
678 +Module['ALLOC_STATIC'] = ALLOC_STATIC;
679 +Module['ALLOC_DYNAMIC'] = ALLOC_DYNAMIC;
680 +Module['ALLOC_NONE'] = ALLOC_NONE;
681 +
682 +// allocate(): This is for internal use. You can use it yourself as well, but the interface
683 +// is a little tricky (see docs right below). The reason is that it is optimized
684 +// for multiple syntaxes to save space in generated code. So you should
685 +// normally not use allocate(), and instead allocate memory using _malloc(),
686 +// initialize it with setValue(), and so forth.
687 +// @slab: An array of data, or a number. If a number, then the size of the block to allocate,
688 +// in *bytes* (note that this is sometimes confusing: the next parameter does not
689 +// affect this!)
690 +// @types: Either an array of types, one for each byte (or 0 if no type at that position),
691 +// or a single type which is used for the entire block. This only matters if there
692 +// is initial data - if @slab is a number, then this does not matter at all and is
693 +// ignored.
694 +// @allocator: How to allocate memory, see ALLOC_*
695 +function allocate(slab, types, allocator, ptr) {
696 + var zeroinit, size;
697 + if (typeof slab === 'number') {
698 + zeroinit = true;
699 + size = slab;
700 + } else {
701 + zeroinit = false;
702 + size = slab.length;
703 + }
704 +
705 + var singleType = typeof types === 'string' ? types : null;
706 +
707 + var ret;
708 + if (allocator == ALLOC_NONE) {
709 + ret = ptr;
710 + } else {
711 + ret = [_malloc, Runtime.stackAlloc, Runtime.staticAlloc, Runtime.dynamicAlloc][allocator === undefined ? ALLOC_STATIC : allocator](Math.max(size, singleType ? 1 : types.length));
712 + }
713 +
714 + if (zeroinit) {
715 + var ptr = ret, stop;
716 + assert((ret & 3) == 0);
717 + stop = ret + (size & ~3);
718 + for (; ptr < stop; ptr += 4) {
719 + HEAP32[((ptr)>>2)]=0;
720 + }
721 + stop = ret + size;
722 + while (ptr < stop) {
723 + HEAP8[((ptr++)|0)]=0;
724 + }
725 + return ret;
726 + }
727 +
728 + if (singleType === 'i8') {
729 + if (slab.subarray || slab.slice) {
730 + HEAPU8.set(slab, ret);
731 + } else {
732 + HEAPU8.set(new Uint8Array(slab), ret);
733 + }
734 + return ret;
735 + }
736 +
737 + var i = 0, type, typeSize, previousType;
738 + while (i < size) {
739 + var curr = slab[i];
740 +
741 + if (typeof curr === 'function') {
742 + curr = Runtime.getFunctionIndex(curr);
743 + }
744 +
745 + type = singleType || types[i];
746 + if (type === 0) {
747 + i++;
748 + continue;
749 + }
750 + assert(type, 'Must know what type to store in allocate!');
751 +
752 + if (type == 'i64') type = 'i32'; // special case: we have one i32 here, and one i32 later
753 +
754 + setValue(ret+i, curr, type);
755 +
756 + // no need to look up size unless type changes, so cache it
757 + if (previousType !== type) {
758 + typeSize = Runtime.getNativeTypeSize(type);
759 + previousType = type;
760 + }
761 + i += typeSize;
762 + }
763 +
764 + return ret;
765 +}
766 +Module['allocate'] = allocate;
767 +
768 +function Pointer_stringify(ptr, /* optional */ length) {
769 + // TODO: use TextDecoder
770 + // Find the length, and check for UTF while doing so
771 + var hasUtf = false;
772 + var t;
773 + var i = 0;
774 + while (1) {
775 + assert(ptr + i < TOTAL_MEMORY);
776 + t = HEAPU8[(((ptr)+(i))|0)];
777 + if (t >= 128) hasUtf = true;
778 + else if (t == 0 && !length) break;
779 + i++;
780 + if (length && i == length) break;
781 + }
782 + if (!length) length = i;
783 +
784 + var ret = '';
785 +
786 + if (!hasUtf) {
787 + var MAX_CHUNK = 1024; // split up into chunks, because .apply on a huge string can overflow the stack
788 + var curr;
789 + while (length > 0) {
790 + curr = String.fromCharCode.apply(String, HEAPU8.subarray(ptr, ptr + Math.min(length, MAX_CHUNK)));
791 + ret = ret ? ret + curr : curr;
792 + ptr += MAX_CHUNK;
793 + length -= MAX_CHUNK;
794 + }
795 + return ret;
796 + }
797 +
798 + var utf8 = new Runtime.UTF8Processor();
799 + for (i = 0; i < length; i++) {
800 + assert(ptr + i < TOTAL_MEMORY);
801 + t = HEAPU8[(((ptr)+(i))|0)];
802 + ret += utf8.processCChar(t);
803 + }
804 + return ret;
805 +}
806 +Module['Pointer_stringify'] = Pointer_stringify;
807 +
808 +// Given a pointer 'ptr' to a null-terminated UTF16LE-encoded string in the emscripten HEAP, returns
809 +// a copy of that string as a Javascript String object.
810 +function UTF16ToString(ptr) {
811 + var i = 0;
812 +
813 + var str = '';
814 + while (1) {
815 + var codeUnit = HEAP16[(((ptr)+(i*2))>>1)];
816 + if (codeUnit == 0)
817 + return str;
818 + ++i;
819 + // fromCharCode constructs a character from a UTF-16 code unit, so we can pass the UTF16 string right through.
820 + str += String.fromCharCode(codeUnit);
821 + }
822 +}
823 +Module['UTF16ToString'] = UTF16ToString;
824 +
825 +// Copies the given Javascript String object 'str' to the emscripten HEAP at address 'outPtr',
826 +// null-terminated and encoded in UTF16LE form. The copy will require at most (str.length*2+1)*2 bytes of space in the HEAP.
827 +function stringToUTF16(str, outPtr) {
828 + for(var i = 0; i < str.length; ++i) {
829 + // charCodeAt returns a UTF-16 encoded code unit, so it can be directly written to the HEAP.
830 + var codeUnit = str.charCodeAt(i); // possibly a lead surrogate
831 + HEAP16[(((outPtr)+(i*2))>>1)]=codeUnit;
832 + }
833 + // Null-terminate the pointer to the HEAP.
834 + HEAP16[(((outPtr)+(str.length*2))>>1)]=0;
835 +}
836 +Module['stringToUTF16'] = stringToUTF16;
837 +
838 +// Given a pointer 'ptr' to a null-terminated UTF32LE-encoded string in the emscripten HEAP, returns
839 +// a copy of that string as a Javascript String object.
840 +function UTF32ToString(ptr) {
841 + var i = 0;
842 +
843 + var str = '';
844 + while (1) {
845 + var utf32 = HEAP32[(((ptr)+(i*4))>>2)];
846 + if (utf32 == 0)
847 + return str;
848 + ++i;
849 + // Gotcha: fromCharCode constructs a character from a UTF-16 encoded code (pair), not from a Unicode code point! So encode the code point to UTF-16 for constructing.
850 + if (utf32 >= 0x10000) {
851 + var ch = utf32 - 0x10000;
852 + str += String.fromCharCode(0xD800 | (ch >> 10), 0xDC00 | (ch & 0x3FF));
853 + } else {
854 + str += String.fromCharCode(utf32);
855 + }
856 + }
857 +}
858 +Module['UTF32ToString'] = UTF32ToString;
859 +
860 +// Copies the given Javascript String object 'str' to the emscripten HEAP at address 'outPtr',
861 +// null-terminated and encoded in UTF32LE form. The copy will require at most (str.length+1)*4 bytes of space in the HEAP,
862 +// but can use less, since str.length does not return the number of characters in the string, but the number of UTF-16 code units in the string.
863 +function stringToUTF32(str, outPtr) {
864 + var iChar = 0;
865 + for(var iCodeUnit = 0; iCodeUnit < str.length; ++iCodeUnit) {
866 + // Gotcha: charCodeAt returns a 16-bit word that is a UTF-16 encoded code unit, not a Unicode code point of the character! We must decode the string to UTF-32 to the heap.
867 + var codeUnit = str.charCodeAt(iCodeUnit); // possibly a lead surrogate
868 + if (codeUnit >= 0xD800 && codeUnit <= 0xDFFF) {
869 + var trailSurrogate = str.charCodeAt(++iCodeUnit);
870 + codeUnit = 0x10000 + ((codeUnit & 0x3FF) << 10) | (trailSurrogate & 0x3FF);
871 + }
872 + HEAP32[(((outPtr)+(iChar*4))>>2)]=codeUnit;
873 + ++iChar;
874 + }
875 + // Null-terminate the pointer to the HEAP.
876 + HEAP32[(((outPtr)+(iChar*4))>>2)]=0;
877 +}
878 +Module['stringToUTF32'] = stringToUTF32;
879 +
880 +function demangle(func) {
881 + try {
882 + // Special-case the entry point, since its name differs from other name mangling.
883 + if (func == 'Object._main' || func == '_main') {
884 + return 'main()';
885 + }
886 + if (typeof func === 'number') func = Pointer_stringify(func);
887 + if (func[0] !== '_') return func;
888 + if (func[1] !== '_') return func; // C function
889 + if (func[2] !== 'Z') return func;
890 + switch (func[3]) {
891 + case 'n': return 'operator new()';
892 + case 'd': return 'operator delete()';
893 + }
894 + var i = 3;
895 + // params, etc.
896 + var basicTypes = {
897 + 'v': 'void',
898 + 'b': 'bool',
899 + 'c': 'char',
900 + 's': 'short',
901 + 'i': 'int',
902 + 'l': 'long',
903 + 'f': 'float',
904 + 'd': 'double',
905 + 'w': 'wchar_t',
906 + 'a': 'signed char',
907 + 'h': 'unsigned char',
908 + 't': 'unsigned short',
909 + 'j': 'unsigned int',
910 + 'm': 'unsigned long',
911 + 'x': 'long long',
912 + 'y': 'unsigned long long',
913 + 'z': '...'
914 + };
915 + function dump(x) {
916 + //return;
917 + if (x) Module.print(x);
918 + Module.print(func);
919 + var pre = '';
920 + for (var a = 0; a < i; a++) pre += ' ';
921 + Module.print (pre + '^');
922 + }
923 + var subs = [];
924 + function parseNested() {
925 + i++;
926 + if (func[i] === 'K') i++; // ignore const
927 + var parts = [];
928 + while (func[i] !== 'E') {
929 + if (func[i] === 'S') { // substitution
930 + i++;
931 + var next = func.indexOf('_', i);
932 + var num = func.substring(i, next) || 0;
933 + parts.push(subs[num] || '?');
934 + i = next+1;
935 + continue;
936 + }
937 + if (func[i] === 'C') { // constructor
938 + parts.push(parts[parts.length-1]);
939 + i += 2;
940 + continue;
941 + }
942 + var size = parseInt(func.substr(i));
943 + var pre = size.toString().length;
944 + if (!size || !pre) { i--; break; } // counter i++ below us
945 + var curr = func.substr(i + pre, size);
946 + parts.push(curr);
947 + subs.push(curr);
948 + i += pre + size;
949 + }
950 + i++; // skip E
951 + return parts;
952 + }
953 + var first = true;
954 + function parse(rawList, limit, allowVoid) { // main parser
955 + limit = limit || Infinity;
956 + var ret = '', list = [];
957 + function flushList() {
958 + return '(' + list.join(', ') + ')';
959 + }
960 + var name;
961 + if (func[i] === 'N') {
962 + // namespaced N-E
963 + name = parseNested().join('::');
964 + limit--;
965 + if (limit === 0) return rawList ? [name] : name;
966 + } else {
967 + // not namespaced
968 + if (func[i] === 'K' || (first && func[i] === 'L')) i++; // ignore const and first 'L'
969 + var size = parseInt(func.substr(i));
970 + if (size) {
971 + var pre = size.toString().length;
972 + name = func.substr(i + pre, size);
973 + i += pre + size;
974 + }
975 + }
976 + first = false;
977 + if (func[i] === 'I') {
978 + i++;
979 + var iList = parse(true);
980 + var iRet = parse(true, 1, true);
981 + ret += iRet[0] + ' ' + name + '<' + iList.join(', ') + '>';
982 + } else {
983 + ret = name;
984 + }
985 + paramLoop: while (i < func.length && limit-- > 0) {
986 + //dump('paramLoop');
987 + var c = func[i++];
988 + if (c in basicTypes) {
989 + list.push(basicTypes[c]);
990 + } else {
991 + switch (c) {
992 + case 'P': list.push(parse(true, 1, true)[0] + '*'); break; // pointer
993 + case 'R': list.push(parse(true, 1, true)[0] + '&'); break; // reference
994 + case 'L': { // literal
995 + i++; // skip basic type
996 + var end = func.indexOf('E', i);
997 + var size = end - i;
998 + list.push(func.substr(i, size));
999 + i += size + 2; // size + 'EE'
1000 + break;
1001 + }
1002 + case 'A': { // array
1003 + var size = parseInt(func.substr(i));
1004 + i += size.toString().length;
1005 + if (func[i] !== '_') throw '?';
1006 + i++; // skip _
1007 + list.push(parse(true, 1, true)[0] + ' [' + size + ']');
1008 + break;
1009 + }
1010 + case 'E': break paramLoop;
1011 + default: ret += '?' + c; break paramLoop;
1012 + }
1013 + }
1014 + }
1015 + if (!allowVoid && list.length === 1 && list[0] === 'void') list = []; // avoid (void)
1016 + return rawList ? list : ret + flushList();
1017 + }
1018 + return parse();
1019 + } catch(e) {
1020 + return func;
1021 + }
1022 +}
1023 +
1024 +function demangleAll(text) {
1025 + return text.replace(/__Z[\w\d_]+/g, function(x) { var y = demangle(x); return x === y ? x : (x + ' [' + y + ']') });
1026 +}
1027 +
1028 +function stackTrace() {
1029 + var stack = new Error().stack;
1030 + return stack ? demangleAll(stack) : '(no stack trace available)'; // Stack trace is not available at least on IE10 and Safari 6.
1031 +}
1032 +
1033 +// Memory management
1034 +
1035 +var PAGE_SIZE = 4096;
1036 +function alignMemoryPage(x) {
1037 + return (x+4095)&-4096;
1038 +}
1039 +
1040 +var HEAP;
1041 +var HEAP8, HEAPU8, HEAP16, HEAPU16, HEAP32, HEAPU32, HEAPF32, HEAPF64;
1042 +
1043 +var STATIC_BASE = 0, STATICTOP = 0, staticSealed = false; // static area
1044 +var STACK_BASE = 0, STACKTOP = 0, STACK_MAX = 0; // stack area
1045 +var DYNAMIC_BASE = 0, DYNAMICTOP = 0; // dynamic area handled by sbrk
1046 +
1047 +function enlargeMemory() {
1048 + abort('Cannot enlarge memory arrays. Either (1) compile with -s TOTAL_MEMORY=X with X higher than the current value ' + TOTAL_MEMORY + ', (2) compile with ALLOW_MEMORY_GROWTH which adjusts the size at runtime but prevents some optimizations, or (3) set Module.TOTAL_MEMORY before the program runs.');
1049 +}
1050 +
1051 +var TOTAL_STACK = Module['TOTAL_STACK'] || 5242880;
1052 +var TOTAL_MEMORY = Module['TOTAL_MEMORY'] || 16777216;
1053 +var FAST_MEMORY = Module['FAST_MEMORY'] || 2097152;
1054 +
1055 +
1056 +// Initialize the runtime's memory
1057 +// check for full engine support (use string 'subarray' to avoid closure compiler confusion)
1058 +assert(typeof Int32Array !== 'undefined' && typeof Float64Array !== 'undefined' && !!(new Int32Array(1)['subarray']) && !!(new Int32Array(1)['set']),
1059 + 'Cannot fallback to non-typed array case: Code is too specialized');
1060 +
1061 +var buffer = new ArrayBuffer(TOTAL_MEMORY);
1062 +HEAP8 = new Int8Array(buffer);
1063 +HEAP16 = new Int16Array(buffer);
1064 +HEAP32 = new Int32Array(buffer);
1065 +HEAPU8 = new Uint8Array(buffer);
1066 +HEAPU16 = new Uint16Array(buffer);
1067 +HEAPU32 = new Uint32Array(buffer);
1068 +HEAPF32 = new Float32Array(buffer);
1069 +HEAPF64 = new Float64Array(buffer);
1070 +
1071 +// Endianness check (note: assumes compiler arch was little-endian)
1072 +HEAP32[0] = 255;
1073 +assert(HEAPU8[0] === 255 && HEAPU8[3] === 0, 'Typed arrays 2 must be run on a little-endian system');
1074 +
1075 +Module['HEAP'] = HEAP;
1076 +Module['HEAP8'] = HEAP8;
1077 +Module['HEAP16'] = HEAP16;
1078 +Module['HEAP32'] = HEAP32;
1079 +Module['HEAPU8'] = HEAPU8;
1080 +Module['HEAPU16'] = HEAPU16;
1081 +Module['HEAPU32'] = HEAPU32;
1082 +Module['HEAPF32'] = HEAPF32;
1083 +Module['HEAPF64'] = HEAPF64;
1084 +
1085 +function callRuntimeCallbacks(callbacks) {
1086 + while(callbacks.length > 0) {
1087 + var callback = callbacks.shift();
1088 + if (typeof callback == 'function') {
1089 + callback();
1090 + continue;
1091 + }
1092 + var func = callback.func;
1093 + if (typeof func === 'number') {
1094 + if (callback.arg === undefined) {
1095 + Runtime.dynCall('v', func);
1096 + } else {
1097 + Runtime.dynCall('vi', func, [callback.arg]);
1098 + }
1099 + } else {
1100 + func(callback.arg === undefined ? null : callback.arg);
1101 + }
1102 + }
1103 +}
1104 +
1105 +var __ATPRERUN__ = []; // functions called before the runtime is initialized
1106 +var __ATINIT__ = []; // functions called during startup
1107 +var __ATMAIN__ = []; // functions called when main() is to be run
1108 +var __ATEXIT__ = []; // functions called during shutdown
1109 +var __ATPOSTRUN__ = []; // functions called after the runtime has exited
1110 +
1111 +var runtimeInitialized = false;
1112 +
1113 +function preRun() {
1114 + // compatibility - merge in anything from Module['preRun'] at this time
1115 + if (Module['preRun']) {
1116 + if (typeof Module['preRun'] == 'function') Module['preRun'] = [Module['preRun']];
1117 + while (Module['preRun'].length) {
1118 + addOnPreRun(Module['preRun'].shift());
1119 + }
1120 + }
1121 + callRuntimeCallbacks(__ATPRERUN__);
1122 +}
1123 +
1124 +function ensureInitRuntime() {
1125 + if (runtimeInitialized) return;
1126 + runtimeInitialized = true;
1127 + callRuntimeCallbacks(__ATINIT__);
1128 +}
1129 +
1130 +function preMain() {
1131 + callRuntimeCallbacks(__ATMAIN__);
1132 +}
1133 +
1134 +function exitRuntime() {
1135 + callRuntimeCallbacks(__ATEXIT__);
1136 +}
1137 +
1138 +function postRun() {
1139 + // compatibility - merge in anything from Module['postRun'] at this time
1140 + if (Module['postRun']) {
1141 + if (typeof Module['postRun'] == 'function') Module['postRun'] = [Module['postRun']];
1142 + while (Module['postRun'].length) {
1143 + addOnPostRun(Module['postRun'].shift());
1144 + }
1145 + }
1146 + callRuntimeCallbacks(__ATPOSTRUN__);
1147 +}
1148 +
1149 +function addOnPreRun(cb) {
1150 + __ATPRERUN__.unshift(cb);
1151 +}
1152 +Module['addOnPreRun'] = Module.addOnPreRun = addOnPreRun;
1153 +
1154 +function addOnInit(cb) {
1155 + __ATINIT__.unshift(cb);
1156 +}
1157 +Module['addOnInit'] = Module.addOnInit = addOnInit;
1158 +
1159 +function addOnPreMain(cb) {
1160 + __ATMAIN__.unshift(cb);
1161 +}
1162 +Module['addOnPreMain'] = Module.addOnPreMain = addOnPreMain;
1163 +
1164 +function addOnExit(cb) {
1165 + __ATEXIT__.unshift(cb);
1166 +}
1167 +Module['addOnExit'] = Module.addOnExit = addOnExit;
1168 +
1169 +function addOnPostRun(cb) {
1170 + __ATPOSTRUN__.unshift(cb);
1171 +}
1172 +Module['addOnPostRun'] = Module.addOnPostRun = addOnPostRun;
1173 +
1174 +// Tools
1175 +
1176 +// This processes a JS string into a C-line array of numbers, 0-terminated.
1177 +// For LLVM-originating strings, see parser.js:parseLLVMString function
1178 +function intArrayFromString(stringy, dontAddNull, length /* optional */) {
1179 + var ret = (new Runtime.UTF8Processor()).processJSString(stringy);
1180 + if (length) {
1181 + ret.length = length;
1182 + }
1183 + if (!dontAddNull) {
1184 + ret.push(0);
1185 + }
1186 + return ret;
1187 +}
1188 +Module['intArrayFromString'] = intArrayFromString;
1189 +
1190 +function intArrayToString(array) {
1191 + var ret = [];
1192 + for (var i = 0; i < array.length; i++) {
1193 + var chr = array[i];
1194 + if (chr > 0xFF) {
1195 + assert(false, 'Character code ' + chr + ' (' + String.fromCharCode(chr) + ') at offset ' + i + ' not in 0x00-0xFF.');
1196 + chr &= 0xFF;
1197 + }
1198 + ret.push(String.fromCharCode(chr));
1199 + }
1200 + return ret.join('');
1201 +}
1202 +Module['intArrayToString'] = intArrayToString;
1203 +
1204 +// Write a Javascript array to somewhere in the heap
1205 +function writeStringToMemory(string, buffer, dontAddNull) {
1206 + var array = intArrayFromString(string, dontAddNull);
1207 + var i = 0;
1208 + while (i < array.length) {
1209 + var chr = array[i];
1210 + HEAP8[(((buffer)+(i))|0)]=chr;
1211 + i = i + 1;
1212 + }
1213 +}
1214 +Module['writeStringToMemory'] = writeStringToMemory;
1215 +
1216 +function writeArrayToMemory(array, buffer) {
1217 + for (var i = 0; i < array.length; i++) {
1218 + HEAP8[(((buffer)+(i))|0)]=array[i];
1219 + }
1220 +}
1221 +Module['writeArrayToMemory'] = writeArrayToMemory;
1222 +
1223 +function writeAsciiToMemory(str, buffer, dontAddNull) {
1224 + for (var i = 0; i < str.length; i++) {
1225 + assert(str.charCodeAt(i) === str.charCodeAt(i)&0xff);
1226 + HEAP8[(((buffer)+(i))|0)]=str.charCodeAt(i);
1227 + }
1228 + if (!dontAddNull) HEAP8[(((buffer)+(str.length))|0)]=0;
1229 +}
1230 +Module['writeAsciiToMemory'] = writeAsciiToMemory;
1231 +
1232 +function unSign(value, bits, ignore, sig) {
1233 + if (value >= 0) {
1234 + return value;
1235 + }
1236 + return bits <= 32 ? 2*Math.abs(1 << (bits-1)) + value // Need some trickery, since if bits == 32, we are right at the limit of the bits JS uses in bitshifts
1237 + : Math.pow(2, bits) + value;
1238 +}
1239 +function reSign(value, bits, ignore, sig) {
1240 + if (value <= 0) {
1241 + return value;
1242 + }
1243 + var half = bits <= 32 ? Math.abs(1 << (bits-1)) // abs is needed if bits == 32
1244 + : Math.pow(2, bits-1);
1245 + if (value >= half && (bits <= 32 || value > half)) { // for huge values, we can hit the precision limit and always get true here. so don't do that
1246 + // but, in general there is no perfect solution here. With 64-bit ints, we get rounding and errors
1247 + // TODO: In i64 mode 1, resign the two parts separately and safely
1248 + value = -2*half + value; // Cannot bitshift half, as it may be at the limit of the bits JS uses in bitshifts
1249 + }
1250 + return value;
1251 +}
1252 +
1253 +// check for imul support, and also for correctness ( https://bugs.webkit.org/show_bug.cgi?id=126345 )
1254 +if (!Math['imul'] || Math['imul'](0xffffffff, 5) !== -5) Math['imul'] = function imul(a, b) {
1255 + var ah = a >>> 16;
1256 + var al = a & 0xffff;
1257 + var bh = b >>> 16;
1258 + var bl = b & 0xffff;
1259 + return (al*bl + ((ah*bl + al*bh) << 16))|0;
1260 +};
1261 +Math.imul = Math['imul'];
1262 +
1263 +
1264 +var Math_abs = Math.abs;
1265 +var Math_cos = Math.cos;
1266 +var Math_sin = Math.sin;
1267 +var Math_tan = Math.tan;
1268 +var Math_acos = Math.acos;
1269 +var Math_asin = Math.asin;
1270 +var Math_atan = Math.atan;
1271 +var Math_atan2 = Math.atan2;
1272 +var Math_exp = Math.exp;
1273 +var Math_log = Math.log;
1274 +var Math_sqrt = Math.sqrt;
1275 +var Math_ceil = Math.ceil;
1276 +var Math_floor = Math.floor;
1277 +var Math_pow = Math.pow;
1278 +var Math_imul = Math.imul;
1279 +var Math_fround = Math.fround;
1280 +var Math_min = Math.min;
1281 +
1282 +// A counter of dependencies for calling run(). If we need to
1283 +// do asynchronous work before running, increment this and
1284 +// decrement it. Incrementing must happen in a place like
1285 +// PRE_RUN_ADDITIONS (used by emcc to add file preloading).
1286 +// Note that you can add dependencies in preRun, even though
1287 +// it happens right before run - run will be postponed until
1288 +// the dependencies are met.
1289 +var runDependencies = 0;
1290 +var runDependencyWatcher = null;
1291 +var dependenciesFulfilled = null; // overridden to take different actions when all run dependencies are fulfilled
1292 +var runDependencyTracking = {};
1293 +
1294 +function addRunDependency(id) {
1295 + runDependencies++;
1296 + if (Module['monitorRunDependencies']) {
1297 + Module['monitorRunDependencies'](runDependencies);
1298 + }
1299 + if (id) {
1300 + assert(!runDependencyTracking[id]);
1301 + runDependencyTracking[id] = 1;
1302 + if (runDependencyWatcher === null && typeof setInterval !== 'undefined') {
1303 + // Check for missing dependencies every few seconds
1304 + runDependencyWatcher = setInterval(function() {
1305 + var shown = false;
1306 + for (var dep in runDependencyTracking) {
1307 + if (!shown) {
1308 + shown = true;
1309 + Module.printErr('still waiting on run dependencies:');
1310 + }
1311 + Module.printErr('dependency: ' + dep);
1312 + }
1313 + if (shown) {
1314 + Module.printErr('(end of list)');
1315 + }
1316 + }, 10000);
1317 + }
1318 + } else {
1319 + Module.printErr('warning: run dependency added without ID');
1320 + }
1321 +}
1322 +Module['addRunDependency'] = addRunDependency;
1323 +function removeRunDependency(id) {
1324 + runDependencies--;
1325 + if (Module['monitorRunDependencies']) {
1326 + Module['monitorRunDependencies'](runDependencies);
1327 + }
1328 + if (id) {
1329 + assert(runDependencyTracking[id]);
1330 + delete runDependencyTracking[id];
1331 + } else {
1332 + Module.printErr('warning: run dependency removed without ID');
1333 + }
1334 + if (runDependencies == 0) {
1335 + if (runDependencyWatcher !== null) {
1336 + clearInterval(runDependencyWatcher);
1337 + runDependencyWatcher = null;
1338 + }
1339 + if (dependenciesFulfilled) {
1340 + var callback = dependenciesFulfilled;
1341 + dependenciesFulfilled = null;
1342 + callback(); // can add another dependenciesFulfilled
1343 + }
1344 + }
1345 +}
1346 +Module['removeRunDependency'] = removeRunDependency;
1347 +
1348 +Module["preloadedImages"] = {}; // maps url to image data
1349 +Module["preloadedAudios"] = {}; // maps url to audio data
1350 +
1351 +
1352 +var memoryInitializer = null;
1353 +
1354 +// === Body ===
1355 +
1356 +
1357 +
1358 +STATIC_BASE = 8;
1359 +
1360 +STATICTOP = STATIC_BASE + 504;
1361 +
1362 +
1363 +/* global initializers */ __ATINIT__.push({ func: function() { runPostSets() } });
1364 +
1365 +
1366 +
1367 +
1368 +
1369 +/* memory initializer */ allocate([255,255,255,0,0,0,0,0], "i8", ALLOC_NONE, Runtime.GLOBAL_BASE);
1370 +function runPostSets() {
1371 +
1372 +
1373 +}
1374 +
1375 +var tempDoublePtr = Runtime.alignMemory(allocate(12, "i8", ALLOC_STATIC), 8);
1376 +
1377 +assert(tempDoublePtr % 8 == 0);
1378 +
1379 +function copyTempFloat(ptr) { // functions, because inlining this code increases code size too much
1380 +
1381 + HEAP8[tempDoublePtr] = HEAP8[ptr];
1382 +
1383 + HEAP8[tempDoublePtr+1] = HEAP8[ptr+1];
1384 +
1385 + HEAP8[tempDoublePtr+2] = HEAP8[ptr+2];
1386 +
1387 + HEAP8[tempDoublePtr+3] = HEAP8[ptr+3];
1388 +
1389 +}
1390 +
1391 +function copyTempDouble(ptr) {
1392 +
1393 + HEAP8[tempDoublePtr] = HEAP8[ptr];
1394 +
1395 + HEAP8[tempDoublePtr+1] = HEAP8[ptr+1];
1396 +
1397 + HEAP8[tempDoublePtr+2] = HEAP8[ptr+2];
1398 +
1399 + HEAP8[tempDoublePtr+3] = HEAP8[ptr+3];
1400 +
1401 + HEAP8[tempDoublePtr+4] = HEAP8[ptr+4];
1402 +
1403 + HEAP8[tempDoublePtr+5] = HEAP8[ptr+5];
1404 +
1405 + HEAP8[tempDoublePtr+6] = HEAP8[ptr+6];
1406 +
1407 + HEAP8[tempDoublePtr+7] = HEAP8[ptr+7];
1408 +
1409 +}
1410 +
1411 +
1412 +
1413 + function _memset(ptr, value, num) {
1414 + ptr = ptr|0; value = value|0; num = num|0;
1415 + var stop = 0, value4 = 0, stop4 = 0, unaligned = 0;
1416 + stop = (ptr + num)|0;
1417 + if ((num|0) >= 20) {
1418 + // This is unaligned, but quite large, so work hard to get to aligned settings
1419 + value = value & 0xff;
1420 + unaligned = ptr & 3;
1421 + value4 = value | (value << 8) | (value << 16) | (value << 24);
1422 + stop4 = stop & ~3;
1423 + if (unaligned) {
1424 + unaligned = (ptr + 4 - unaligned)|0;
1425 + while ((ptr|0) < (unaligned|0)) { // no need to check for stop, since we have large num
1426 + HEAP8[(ptr)]=value;
1427 + ptr = (ptr+1)|0;
1428 + }
1429 + }
1430 + while ((ptr|0) < (stop4|0)) {
1431 + HEAP32[((ptr)>>2)]=value4;
1432 + ptr = (ptr+4)|0;
1433 + }
1434 + }
1435 + while ((ptr|0) < (stop|0)) {
1436 + HEAP8[(ptr)]=value;
1437 + ptr = (ptr+1)|0;
1438 + }
1439 + return (ptr-num)|0;
1440 + }var _llvm_memset_p0i8_i32=_memset;
1441 +
1442 +
1443 + function _memcpy(dest, src, num) {
1444 + dest = dest|0; src = src|0; num = num|0;
1445 + var ret = 0;
1446 + ret = dest|0;
1447 + if ((dest&3) == (src&3)) {
1448 + while (dest & 3) {
1449 + if ((num|0) == 0) return ret|0;
1450 + HEAP8[(dest)]=HEAP8[(src)];
1451 + dest = (dest+1)|0;
1452 + src = (src+1)|0;
1453 + num = (num-1)|0;
1454 + }
1455 + while ((num|0) >= 4) {
1456 + HEAP32[((dest)>>2)]=HEAP32[((src)>>2)];
1457 + dest = (dest+4)|0;
1458 + src = (src+4)|0;
1459 + num = (num-4)|0;
1460 + }
1461 + }
1462 + while ((num|0) > 0) {
1463 + HEAP8[(dest)]=HEAP8[(src)];
1464 + dest = (dest+1)|0;
1465 + src = (src+1)|0;
1466 + num = (num-1)|0;
1467 + }
1468 + return ret|0;
1469 + }var _llvm_memcpy_p0i8_p0i8_i32=_memcpy;
1470 +
1471 + function _abort() {
1472 + Module['abort']();
1473 + }
1474 +
1475 +
1476 +
1477 + var ___errno_state=0;function ___setErrNo(value) {
1478 + // For convenient setting and returning of errno.
1479 + HEAP32[((___errno_state)>>2)]=value;
1480 + return value;
1481 + }function ___errno_location() {
1482 + return ___errno_state;
1483 + }
1484 +
1485 + function _sbrk(bytes) {
1486 + // Implement a Linux-like 'memory area' for our 'process'.
1487 + // Changes the size of the memory area by |bytes|; returns the
1488 + // address of the previous top ('break') of the memory area
1489 + // We control the "dynamic" memory - DYNAMIC_BASE to DYNAMICTOP
1490 + var self = _sbrk;
1491 + if (!self.called) {
1492 + DYNAMICTOP = alignMemoryPage(DYNAMICTOP); // make sure we start out aligned
1493 + self.called = true;
1494 + assert(Runtime.dynamicAlloc);
1495 + self.alloc = Runtime.dynamicAlloc;
1496 + Runtime.dynamicAlloc = function() { abort('cannot dynamically allocate, sbrk now has control') };
1497 + }
1498 + var ret = DYNAMICTOP;
1499 + if (bytes != 0) self.alloc(bytes);
1500 + return ret; // Previous break location.
1501 + }
1502 +
1503 +
1504 + var ERRNO_CODES={EPERM:1,ENOENT:2,ESRCH:3,EINTR:4,EIO:5,ENXIO:6,E2BIG:7,ENOEXEC:8,EBADF:9,ECHILD:10,EAGAIN:11,EWOULDBLOCK:11,ENOMEM:12,EACCES:13,EFAULT:14,ENOTBLK:15,EBUSY:16,EEXIST:17,EXDEV:18,ENODEV:19,ENOTDIR:20,EISDIR:21,EINVAL:22,ENFILE:23,EMFILE:24,ENOTTY:25,ETXTBSY:26,EFBIG:27,ENOSPC:28,ESPIPE:29,EROFS:30,EMLINK:31,EPIPE:32,EDOM:33,ERANGE:34,ENOMSG:42,EIDRM:43,ECHRNG:44,EL2NSYNC:45,EL3HLT:46,EL3RST:47,ELNRNG:48,EUNATCH:49,ENOCSI:50,EL2HLT:51,EDEADLK:35,ENOLCK:37,EBADE:52,EBADR:53,EXFULL:54,ENOANO:55,EBADRQC:56,EBADSLT:57,EDEADLOCK:35,EBFONT:59,ENOSTR:60,ENODATA:61,ETIME:62,ENOSR:63,ENONET:64,ENOPKG:65,EREMOTE:66,ENOLINK:67,EADV:68,ESRMNT:69,ECOMM:70,EPROTO:71,EMULTIHOP:72,EDOTDOT:73,EBADMSG:74,ENOTUNIQ:76,EBADFD:77,EREMCHG:78,ELIBACC:79,ELIBBAD:80,ELIBSCN:81,ELIBMAX:82,ELIBEXEC:83,ENOSYS:38,ENOTEMPTY:39,ENAMETOOLONG:36,ELOOP:40,EOPNOTSUPP:95,EPFNOSUPPORT:96,ECONNRESET:104,ENOBUFS:105,EAFNOSUPPORT:97,EPROTOTYPE:91,ENOTSOCK:88,ENOPROTOOPT:92,ESHUTDOWN:108,ECONNREFUSED:111,EADDRINUSE:98,ECONNABORTED:103,ENETUNREACH:101,ENETDOWN:100,ETIMEDOUT:110,EHOSTDOWN:112,EHOSTUNREACH:113,EINPROGRESS:115,EALREADY:114,EDESTADDRREQ:89,EMSGSIZE:90,EPROTONOSUPPORT:93,ESOCKTNOSUPPORT:94,EADDRNOTAVAIL:99,ENETRESET:102,EISCONN:106,ENOTCONN:107,ETOOMANYREFS:109,EUSERS:87,EDQUOT:122,ESTALE:116,ENOTSUP:95,ENOMEDIUM:123,EILSEQ:84,EOVERFLOW:75,ECANCELED:125,ENOTRECOVERABLE:131,EOWNERDEAD:130,ESTRPIPE:86};function _sysconf(name) {
1505 + // long sysconf(int name);
1506 + // http://pubs.opengroup.org/onlinepubs/009695399/functions/sysconf.html
1507 + switch(name) {
1508 + case 30: return PAGE_SIZE;
1509 + case 132:
1510 + case 133:
1511 + case 12:
1512 + case 137:
1513 + case 138:
1514 + case 15:
1515 + case 235:
1516 + case 16:
1517 + case 17:
1518 + case 18:
1519 + case 19:
1520 + case 20:
1521 + case 149:
1522 + case 13:
1523 + case 10:
1524 + case 236:
1525 + case 153:
1526 + case 9:
1527 + case 21:
1528 + case 22:
1529 + case 159:
1530 + case 154:
1531 + case 14:
1532 + case 77:
1533 + case 78:
1534 + case 139:
1535 + case 80:
1536 + case 81:
1537 + case 79:
1538 + case 82:
1539 + case 68:
1540 + case 67:
1541 + case 164:
1542 + case 11:
1543 + case 29:
1544 + case 47:
1545 + case 48:
1546 + case 95:
1547 + case 52:
1548 + case 51:
1549 + case 46:
1550 + return 200809;
1551 + case 27:
1552 + case 246:
1553 + case 127:
1554 + case 128:
1555 + case 23:
1556 + case 24:
1557 + case 160:
1558 + case 161:
1559 + case 181:
1560 + case 182:
1561 + case 242:
1562 + case 183:
1563 + case 184:
1564 + case 243:
1565 + case 244:
1566 + case 245:
1567 + case 165:
1568 + case 178:
1569 + case 179:
1570 + case 49:
1571 + case 50:
1572 + case 168:
1573 + case 169:
1574 + case 175:
1575 + case 170:
1576 + case 171:
1577 + case 172:
1578 + case 97:
1579 + case 76:
1580 + case 32:
1581 + case 173:
1582 + case 35:
1583 + return -1;
1584 + case 176:
1585 + case 177:
1586 + case 7:
1587 + case 155:
1588 + case 8:
1589 + case 157:
1590 + case 125:
1591 + case 126:
1592 + case 92:
1593 + case 93:
1594 + case 129:
1595 + case 130:
1596 + case 131:
1597 + case 94:
1598 + case 91:
1599 + return 1;
1600 + case 74:
1601 + case 60:
1602 + case 69:
1603 + case 70:
1604 + case 4:
1605 + return 1024;
1606 + case 31:
1607 + case 42:
1608 + case 72:
1609 + return 32;
1610 + case 87:
1611 + case 26:
1612 + case 33:
1613 + return 2147483647;
1614 + case 34:
1615 + case 1:
1616 + return 47839;
1617 + case 38:
1618 + case 36:
1619 + return 99;
1620 + case 43:
1621 + case 37:
1622 + return 2048;
1623 + case 0: return 2097152;
1624 + case 3: return 65536;
1625 + case 28: return 32768;
1626 + case 44: return 32767;
1627 + case 75: return 16384;
1628 + case 39: return 1000;
1629 + case 89: return 700;
1630 + case 71: return 256;
1631 + case 40: return 255;
1632 + case 2: return 100;
1633 + case 180: return 64;
1634 + case 25: return 20;
1635 + case 5: return 16;
1636 + case 6: return 6;
1637 + case 73: return 4;
1638 + case 84: return 1;
1639 + }
1640 + ___setErrNo(ERRNO_CODES.EINVAL);
1641 + return -1;
1642 + }
1643 +
1644 + function _time(ptr) {
1645 + var ret = Math.floor(Date.now()/1000);
1646 + if (ptr) {
1647 + HEAP32[((ptr)>>2)]=ret;
1648 + }
1649 + return ret;
1650 + }
1651 +
1652 +
1653 +
1654 +
1655 +
1656 + function _strlen(ptr) {
1657 + ptr = ptr|0;
1658 + var curr = 0;
1659 + curr = ptr;
1660 + while (HEAP8[(curr)]) {
1661 + curr = (curr + 1)|0;
1662 + }
1663 + return (curr - ptr)|0;
1664 + }
1665 +
1666 +
1667 +
1668 +
1669 + var ERRNO_MESSAGES={0:"Success",1:"Not super-user",2:"No such file or directory",3:"No such process",4:"Interrupted system call",5:"I/O error",6:"No such device or address",7:"Arg list too long",8:"Exec format error",9:"Bad file number",10:"No children",11:"No more processes",12:"Not enough core",13:"Permission denied",14:"Bad address",15:"Block device required",16:"Mount device busy",17:"File exists",18:"Cross-device link",19:"No such device",20:"Not a directory",21:"Is a directory",22:"Invalid argument",23:"Too many open files in system",24:"Too many open files",25:"Not a typewriter",26:"Text file busy",27:"File too large",28:"No space left on device",29:"Illegal seek",30:"Read only file system",31:"Too many links",32:"Broken pipe",33:"Math arg out of domain of func",34:"Math result not representable",35:"File locking deadlock error",36:"File or path name too long",37:"No record locks available",38:"Function not implemented",39:"Directory not empty",40:"Too many symbolic links",42:"No message of desired type",43:"Identifier removed",44:"Channel number out of range",45:"Level 2 not synchronized",46:"Level 3 halted",47:"Level 3 reset",48:"Link number out of range",49:"Protocol driver not attached",50:"No CSI structure available",51:"Level 2 halted",52:"Invalid exchange",53:"Invalid request descriptor",54:"Exchange full",55:"No anode",56:"Invalid request code",57:"Invalid slot",59:"Bad font file fmt",60:"Device not a stream",61:"No data (for no delay io)",62:"Timer expired",63:"Out of streams resources",64:"Machine is not on the network",65:"Package not installed",66:"The object is remote",67:"The link has been severed",68:"Advertise error",69:"Srmount error",70:"Communication error on send",71:"Protocol error",72:"Multihop attempted",73:"Cross mount point (not really error)",74:"Trying to read unreadable message",75:"Value too large for defined data type",76:"Given log. name not unique",77:"f.d. invalid for this operation",78:"Remote address changed",79:"Can access a needed shared lib",80:"Accessing a corrupted shared lib",81:".lib section in a.out corrupted",82:"Attempting to link in too many libs",83:"Attempting to exec a shared library",84:"Illegal byte sequence",86:"Streams pipe error",87:"Too many users",88:"Socket operation on non-socket",89:"Destination address required",90:"Message too long",91:"Protocol wrong type for socket",92:"Protocol not available",93:"Unknown protocol",94:"Socket type not supported",95:"Not supported",96:"Protocol family not supported",97:"Address family not supported by protocol family",98:"Address already in use",99:"Address not available",100:"Network interface is not configured",101:"Network is unreachable",102:"Connection reset by network",103:"Connection aborted",104:"Connection reset by peer",105:"No buffer space available",106:"Socket is already connected",107:"Socket is not connected",108:"Can't send after socket shutdown",109:"Too many references",110:"Connection timed out",111:"Connection refused",112:"Host is down",113:"Host is unreachable",114:"Socket already connected",115:"Connection already in progress",116:"Stale file handle",122:"Quota exceeded",123:"No medium (in tape drive)",125:"Operation canceled",130:"Previous owner died",131:"State not recoverable"};
1670 +
1671 + var TTY={ttys:[],init:function () {
1672 + // https://github.com/kripken/emscripten/pull/1555
1673 + // if (ENVIRONMENT_IS_NODE) {
1674 + // // currently, FS.init does not distinguish if process.stdin is a file or TTY
1675 + // // device, it always assumes it's a TTY device. because of this, we're forcing
1676 + // // process.stdin to UTF8 encoding to at least make stdin reading compatible
1677 + // // with text files until FS.init can be refactored.
1678 + // process['stdin']['setEncoding']('utf8');
1679 + // }
1680 + },shutdown:function () {
1681 + // https://github.com/kripken/emscripten/pull/1555
1682 + // if (ENVIRONMENT_IS_NODE) {
1683 + // // inolen: any idea as to why node -e 'process.stdin.read()' wouldn't exit immediately (with process.stdin being a tty)?
1684 + // // isaacs: because now it's reading from the stream, you've expressed interest in it, so that read() kicks off a _read() which creates a ReadReq operation
1685 + // // inolen: I thought read() in that case was a synchronous operation that just grabbed some amount of buffered data if it exists?
1686 + // // isaacs: it is. but it also triggers a _read() call, which calls readStart() on the handle
1687 + // // isaacs: do process.stdin.pause() and i'd think it'd probably close the pending call
1688 + // process['stdin']['pause']();
1689 + // }
1690 + },register:function (dev, ops) {
1691 + TTY.ttys[dev] = { input: [], output: [], ops: ops };
1692 + FS.registerDevice(dev, TTY.stream_ops);
1693 + },stream_ops:{open:function (stream) {
1694 + var tty = TTY.ttys[stream.node.rdev];
1695 + if (!tty) {
1696 + throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
1697 + }
1698 + stream.tty = tty;
1699 + stream.seekable = false;
1700 + },close:function (stream) {
1701 + // flush any pending line data
1702 + if (stream.tty.output.length) {
1703 + stream.tty.ops.put_char(stream.tty, 10);
1704 + }
1705 + },read:function (stream, buffer, offset, length, pos /* ignored */) {
1706 + if (!stream.tty || !stream.tty.ops.get_char) {
1707 + throw new FS.ErrnoError(ERRNO_CODES.ENXIO);
1708 + }
1709 + var bytesRead = 0;
1710 + for (var i = 0; i < length; i++) {
1711 + var result;
1712 + try {
1713 + result = stream.tty.ops.get_char(stream.tty);
1714 + } catch (e) {
1715 + throw new FS.ErrnoError(ERRNO_CODES.EIO);
1716 + }
1717 + if (result === undefined && bytesRead === 0) {
1718 + throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
1719 + }
1720 + if (result === null || result === undefined) break;
1721 + bytesRead++;
1722 + buffer[offset+i] = result;
1723 + }
1724 + if (bytesRead) {
1725 + stream.node.timestamp = Date.now();
1726 + }
1727 + return bytesRead;
1728 + },write:function (stream, buffer, offset, length, pos) {
1729 + if (!stream.tty || !stream.tty.ops.put_char) {
1730 + throw new FS.ErrnoError(ERRNO_CODES.ENXIO);
1731 + }
1732 + for (var i = 0; i < length; i++) {
1733 + try {
1734 + stream.tty.ops.put_char(stream.tty, buffer[offset+i]);
1735 + } catch (e) {
1736 + throw new FS.ErrnoError(ERRNO_CODES.EIO);
1737 + }
1738 + }
1739 + if (length) {
1740 + stream.node.timestamp = Date.now();
1741 + }
1742 + return i;
1743 + }},default_tty_ops:{get_char:function (tty) {
1744 + if (!tty.input.length) {
1745 + var result = null;
1746 + if (ENVIRONMENT_IS_NODE) {
1747 + result = process['stdin']['read']();
1748 + if (!result) {
1749 + if (process['stdin']['_readableState'] && process['stdin']['_readableState']['ended']) {
1750 + return null; // EOF
1751 + }
1752 + return undefined; // no data available
1753 + }
1754 + } else if (typeof window != 'undefined' &&
1755 + typeof window.prompt == 'function') {
1756 + // Browser.
1757 + result = window.prompt('Input: '); // returns null on cancel
1758 + if (result !== null) {
1759 + result += '\n';
1760 + }
1761 + } else if (typeof readline == 'function') {
1762 + // Command line.
1763 + result = readline();
1764 + if (result !== null) {
1765 + result += '\n';
1766 + }
1767 + }
1768 + if (!result) {
1769 + return null;
1770 + }
1771 + tty.input = intArrayFromString(result, true);
1772 + }
1773 + return tty.input.shift();
1774 + },put_char:function (tty, val) {
1775 + if (val === null || val === 10) {
1776 + Module['print'](tty.output.join(''));
1777 + tty.output = [];
1778 + } else {
1779 + tty.output.push(TTY.utf8.processCChar(val));
1780 + }
1781 + }},default_tty1_ops:{put_char:function (tty, val) {
1782 + if (val === null || val === 10) {
1783 + Module['printErr'](tty.output.join(''));
1784 + tty.output = [];
1785 + } else {
1786 + tty.output.push(TTY.utf8.processCChar(val));
1787 + }
1788 + }}};
1789 +
1790 + var MEMFS={ops_table:null,CONTENT_OWNING:1,CONTENT_FLEXIBLE:2,CONTENT_FIXED:3,mount:function (mount) {
1791 + return MEMFS.createNode(null, '/', 16384 | 0777, 0);
1792 + },createNode:function (parent, name, mode, dev) {
1793 + if (FS.isBlkdev(mode) || FS.isFIFO(mode)) {
1794 + // no supported
1795 + throw new FS.ErrnoError(ERRNO_CODES.EPERM);
1796 + }
1797 + if (!MEMFS.ops_table) {
1798 + MEMFS.ops_table = {
1799 + dir: {
1800 + node: {
1801 + getattr: MEMFS.node_ops.getattr,
1802 + setattr: MEMFS.node_ops.setattr,
1803 + lookup: MEMFS.node_ops.lookup,
1804 + mknod: MEMFS.node_ops.mknod,
1805 + mknod: MEMFS.node_ops.mknod,
1806 + rename: MEMFS.node_ops.rename,
1807 + unlink: MEMFS.node_ops.unlink,
1808 + rmdir: MEMFS.node_ops.rmdir,
1809 + readdir: MEMFS.node_ops.readdir,
1810 + symlink: MEMFS.node_ops.symlink
1811 + },
1812 + stream: {
1813 + llseek: MEMFS.stream_ops.llseek
1814 + }
1815 + },
1816 + file: {
1817 + node: {
1818 + getattr: MEMFS.node_ops.getattr,
1819 + setattr: MEMFS.node_ops.setattr
1820 + },
1821 + stream: {
1822 + llseek: MEMFS.stream_ops.llseek,
1823 + read: MEMFS.stream_ops.read,
1824 + write: MEMFS.stream_ops.write,
1825 + allocate: MEMFS.stream_ops.allocate,
1826 + mmap: MEMFS.stream_ops.mmap
1827 + }
1828 + },
1829 + link: {
1830 + node: {
1831 + getattr: MEMFS.node_ops.getattr,
1832 + setattr: MEMFS.node_ops.setattr,
1833 + readlink: MEMFS.node_ops.readlink
1834 + },
1835 + stream: {}
1836 + },
1837 + chrdev: {
1838 + node: {
1839 + getattr: MEMFS.node_ops.getattr,
1840 + setattr: MEMFS.node_ops.setattr
1841 + },
1842 + stream: FS.chrdev_stream_ops
1843 + },
1844 + };
1845 + }
1846 + var node = FS.createNode(parent, name, mode, dev);
1847 + if (FS.isDir(node.mode)) {
1848 + node.node_ops = MEMFS.ops_table.dir.node;
1849 + node.stream_ops = MEMFS.ops_table.dir.stream;
1850 + node.contents = {};
1851 + } else if (FS.isFile(node.mode)) {
1852 + node.node_ops = MEMFS.ops_table.file.node;
1853 + node.stream_ops = MEMFS.ops_table.file.stream;
1854 + node.contents = [];
1855 + node.contentMode = MEMFS.CONTENT_FLEXIBLE;
1856 + } else if (FS.isLink(node.mode)) {
1857 + node.node_ops = MEMFS.ops_table.link.node;
1858 + node.stream_ops = MEMFS.ops_table.link.stream;
1859 + } else if (FS.isChrdev(node.mode)) {
1860 + node.node_ops = MEMFS.ops_table.chrdev.node;
1861 + node.stream_ops = MEMFS.ops_table.chrdev.stream;
1862 + }
1863 + node.timestamp = Date.now();
1864 + // add the new node to the parent
1865 + if (parent) {
1866 + parent.contents[name] = node;
1867 + }
1868 + return node;
1869 + },ensureFlexible:function (node) {
1870 + if (node.contentMode !== MEMFS.CONTENT_FLEXIBLE) {
1871 + var contents = node.contents;
1872 + node.contents = Array.prototype.slice.call(contents);
1873 + node.contentMode = MEMFS.CONTENT_FLEXIBLE;
1874 + }
1875 + },node_ops:{getattr:function (node) {
1876 + var attr = {};
1877 + // device numbers reuse inode numbers.
1878 + attr.dev = FS.isChrdev(node.mode) ? node.id : 1;
1879 + attr.ino = node.id;
1880 + attr.mode = node.mode;
1881 + attr.nlink = 1;
1882 + attr.uid = 0;
1883 + attr.gid = 0;
1884 + attr.rdev = node.rdev;
1885 + if (FS.isDir(node.mode)) {
1886 + attr.size = 4096;
1887 + } else if (FS.isFile(node.mode)) {
1888 + attr.size = node.contents.length;
1889 + } else if (FS.isLink(node.mode)) {
1890 + attr.size = node.link.length;
1891 + } else {
1892 + attr.size = 0;
1893 + }
1894 + attr.atime = new Date(node.timestamp);
1895 + attr.mtime = new Date(node.timestamp);
1896 + attr.ctime = new Date(node.timestamp);
1897 + // NOTE: In our implementation, st_blocks = Math.ceil(st_size/st_blksize),
1898 + // but this is not required by the standard.
1899 + attr.blksize = 4096;
1900 + attr.blocks = Math.ceil(attr.size / attr.blksize);
1901 + return attr;
1902 + },setattr:function (node, attr) {
1903 + if (attr.mode !== undefined) {
1904 + node.mode = attr.mode;
1905 + }
1906 + if (attr.timestamp !== undefined) {
1907 + node.timestamp = attr.timestamp;
1908 + }
1909 + if (attr.size !== undefined) {
1910 + MEMFS.ensureFlexible(node);
1911 + var contents = node.contents;
1912 + if (attr.size < contents.length) contents.length = attr.size;
1913 + else while (attr.size > contents.length) contents.push(0);
1914 + }
1915 + },lookup:function (parent, name) {
1916 + throw FS.genericErrors[ERRNO_CODES.ENOENT];
1917 + },mknod:function (parent, name, mode, dev) {
1918 + return MEMFS.createNode(parent, name, mode, dev);
1919 + },rename:function (old_node, new_dir, new_name) {
1920 + // if we're overwriting a directory at new_name, make sure it's empty.
1921 + if (FS.isDir(old_node.mode)) {
1922 + var new_node;
1923 + try {
1924 + new_node = FS.lookupNode(new_dir, new_name);
1925 + } catch (e) {
1926 + }
1927 + if (new_node) {
1928 + for (var i in new_node.contents) {
1929 + throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY);
1930 + }
1931 + }
1932 + }
1933 + // do the internal rewiring
1934 + delete old_node.parent.contents[old_node.name];
1935 + old_node.name = new_name;
1936 + new_dir.contents[new_name] = old_node;
1937 + old_node.parent = new_dir;
1938 + },unlink:function (parent, name) {
1939 + delete parent.contents[name];
1940 + },rmdir:function (parent, name) {
1941 + var node = FS.lookupNode(parent, name);
1942 + for (var i in node.contents) {
1943 + throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY);
1944 + }
1945 + delete parent.contents[name];
1946 + },readdir:function (node) {
1947 + var entries = ['.', '..']
1948 + for (var key in node.contents) {
1949 + if (!node.contents.hasOwnProperty(key)) {
1950 + continue;
1951 + }
1952 + entries.push(key);
1953 + }
1954 + return entries;
1955 + },symlink:function (parent, newname, oldpath) {
1956 + var node = MEMFS.createNode(parent, newname, 0777 | 40960, 0);
1957 + node.link = oldpath;
1958 + return node;
1959 + },readlink:function (node) {
1960 + if (!FS.isLink(node.mode)) {
1961 + throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
1962 + }
1963 + return node.link;
1964 + }},stream_ops:{read:function (stream, buffer, offset, length, position) {
1965 + var contents = stream.node.contents;
1966 + if (position >= contents.length)
1967 + return 0;
1968 + var size = Math.min(contents.length - position, length);
1969 + assert(size >= 0);
1970 + if (size > 8 && contents.subarray) { // non-trivial, and typed array
1971 + buffer.set(contents.subarray(position, position + size), offset);
1972 + } else
1973 + {
1974 + for (var i = 0; i < size; i++) {
1975 + buffer[offset + i] = contents[position + i];
1976 + }
1977 + }
1978 + return size;
1979 + },write:function (stream, buffer, offset, length, position, canOwn) {
1980 + var node = stream.node;
1981 + node.timestamp = Date.now();
1982 + var contents = node.contents;
1983 + if (length && contents.length === 0 && position === 0 && buffer.subarray) {
1984 + // just replace it with the new data
1985 + assert(buffer.length);
1986 + if (canOwn && offset === 0) {
1987 + node.contents = buffer; // this could be a subarray of Emscripten HEAP, or allocated from some other source.
1988 + node.contentMode = (buffer.buffer === HEAP8.buffer) ? MEMFS.CONTENT_OWNING : MEMFS.CONTENT_FIXED;
1989 + } else {
1990 + node.contents = new Uint8Array(buffer.subarray(offset, offset+length));
1991 + node.contentMode = MEMFS.CONTENT_FIXED;
1992 + }
1993 + return length;
1994 + }
1995 + MEMFS.ensureFlexible(node);
1996 + var contents = node.contents;
1997 + while (contents.length < position) contents.push(0);
1998 + for (var i = 0; i < length; i++) {
1999 + contents[position + i] = buffer[offset + i];
2000 + }
2001 + return length;
2002 + },llseek:function (stream, offset, whence) {
2003 + var position = offset;
2004 + if (whence === 1) { // SEEK_CUR.
2005 + position += stream.position;
2006 + } else if (whence === 2) { // SEEK_END.
2007 + if (FS.isFile(stream.node.mode)) {
2008 + position += stream.node.contents.length;
2009 + }
2010 + }
2011 + if (position < 0) {
2012 + throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
2013 + }
2014 + stream.ungotten = [];
2015 + stream.position = position;
2016 + return position;
2017 + },allocate:function (stream, offset, length) {
2018 + MEMFS.ensureFlexible(stream.node);
2019 + var contents = stream.node.contents;
2020 + var limit = offset + length;
2021 + while (limit > contents.length) contents.push(0);
2022 + },mmap:function (stream, buffer, offset, length, position, prot, flags) {
2023 + if (!FS.isFile(stream.node.mode)) {
2024 + throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
2025 + }
2026 + var ptr;
2027 + var allocated;
2028 + var contents = stream.node.contents;
2029 + // Only make a new copy when MAP_PRIVATE is specified.
2030 + if ( !(flags & 2) &&
2031 + (contents.buffer === buffer || contents.buffer === buffer.buffer) ) {
2032 + // We can't emulate MAP_SHARED when the file is not backed by the buffer
2033 + // we're mapping to (e.g. the HEAP buffer).
2034 + allocated = false;
2035 + ptr = contents.byteOffset;
2036 + } else {
2037 + // Try to avoid unnecessary slices.
2038 + if (position > 0 || position + length < contents.length) {
2039 + if (contents.subarray) {
2040 + contents = contents.subarray(position, position + length);
2041 + } else {
2042 + contents = Array.prototype.slice.call(contents, position, position + length);
2043 + }
2044 + }
2045 + allocated = true;
2046 + ptr = _malloc(length);
2047 + if (!ptr) {
2048 + throw new FS.ErrnoError(ERRNO_CODES.ENOMEM);
2049 + }
2050 + buffer.set(contents, ptr);
2051 + }
2052 + return { ptr: ptr, allocated: allocated };
2053 + }}};
2054 +
2055 + var IDBFS={dbs:{},indexedDB:function () {
2056 + return window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
2057 + },DB_VERSION:20,DB_STORE_NAME:"FILE_DATA",mount:function (mount) {
2058 + return MEMFS.mount.apply(null, arguments);
2059 + },syncfs:function (mount, populate, callback) {
2060 + IDBFS.getLocalSet(mount, function(err, local) {
2061 + if (err) return callback(err);
2062 +
2063 + IDBFS.getRemoteSet(mount, function(err, remote) {
2064 + if (err) return callback(err);
2065 +
2066 + var src = populate ? remote : local;
2067 + var dst = populate ? local : remote;
2068 +
2069 + IDBFS.reconcile(src, dst, callback);
2070 + });
2071 + });
2072 + },reconcile:function (src, dst, callback) {
2073 + var total = 0;
2074 +
2075 + var create = {};
2076 + for (var key in src.files) {
2077 + if (!src.files.hasOwnProperty(key)) continue;
2078 + var e = src.files[key];
2079 + var e2 = dst.files[key];
2080 + if (!e2 || e.timestamp > e2.timestamp) {
2081 + create[key] = e;
2082 + total++;
2083 + }
2084 + }
2085 +
2086 + var remove = {};
2087 + for (var key in dst.files) {
2088 + if (!dst.files.hasOwnProperty(key)) continue;
2089 + var e = dst.files[key];
2090 + var e2 = src.files[key];
2091 + if (!e2) {
2092 + remove[key] = e;
2093 + total++;
2094 + }
2095 + }
2096 +
2097 + if (!total) {
2098 + // early out
2099 + return callback(null);
2100 + }
2101 +
2102 + var completed = 0;
2103 + function done(err) {
2104 + if (err) return callback(err);
2105 + if (++completed >= total) {
2106 + return callback(null);
2107 + }
2108 + };
2109 +
2110 + // create a single transaction to handle and IDB reads / writes we'll need to do
2111 + var db = src.type === 'remote' ? src.db : dst.db;
2112 + var transaction = db.transaction([IDBFS.DB_STORE_NAME], 'readwrite');
2113 + transaction.onerror = function transaction_onerror() { callback(this.error); };
2114 + var store = transaction.objectStore(IDBFS.DB_STORE_NAME);
2115 +
2116 + for (var path in create) {
2117 + if (!create.hasOwnProperty(path)) continue;
2118 + var entry = create[path];
2119 +
2120 + if (dst.type === 'local') {
2121 + // save file to local
2122 + try {
2123 + if (FS.isDir(entry.mode)) {
2124 + FS.mkdir(path, entry.mode);
2125 + } else if (FS.isFile(entry.mode)) {
2126 + var stream = FS.open(path, 'w+', 0666);
2127 + FS.write(stream, entry.contents, 0, entry.contents.length, 0, true /* canOwn */);
2128 + FS.close(stream);
2129 + }
2130 + done(null);
2131 + } catch (e) {
2132 + return done(e);
2133 + }
2134 + } else {
2135 + // save file to IDB
2136 + var req = store.put(entry, path);
2137 + req.onsuccess = function req_onsuccess() { done(null); };
2138 + req.onerror = function req_onerror() { done(this.error); };
2139 + }
2140 + }
2141 +
2142 + for (var path in remove) {
2143 + if (!remove.hasOwnProperty(path)) continue;
2144 + var entry = remove[path];
2145 +
2146 + if (dst.type === 'local') {
2147 + // delete file from local
2148 + try {
2149 + if (FS.isDir(entry.mode)) {
2150 + // TODO recursive delete?
2151 + FS.rmdir(path);
2152 + } else if (FS.isFile(entry.mode)) {
2153 + FS.unlink(path);
2154 + }
2155 + done(null);
2156 + } catch (e) {
2157 + return done(e);
2158 + }
2159 + } else {
2160 + // delete file from IDB
2161 + var req = store.delete(path);
2162 + req.onsuccess = function req_onsuccess() { done(null); };
2163 + req.onerror = function req_onerror() { done(this.error); };
2164 + }
2165 + }
2166 + },getLocalSet:function (mount, callback) {
2167 + var files = {};
2168 +
2169 + function isRealDir(p) {
2170 + return p !== '.' && p !== '..';
2171 + };
2172 + function toAbsolute(root) {
2173 + return function(p) {
2174 + return PATH.join2(root, p);
2175 + }
2176 + };
2177 +
2178 + var check = FS.readdir(mount.mountpoint)
2179 + .filter(isRealDir)
2180 + .map(toAbsolute(mount.mountpoint));
2181 +
2182 + while (check.length) {
2183 + var path = check.pop();
2184 + var stat, node;
2185 +
2186 + try {
2187 + var lookup = FS.lookupPath(path);
2188 + node = lookup.node;
2189 + stat = FS.stat(path);
2190 + } catch (e) {
2191 + return callback(e);
2192 + }
2193 +
2194 + if (FS.isDir(stat.mode)) {
2195 + check.push.apply(check, FS.readdir(path)
2196 + .filter(isRealDir)
2197 + .map(toAbsolute(path)));
2198 +
2199 + files[path] = { mode: stat.mode, timestamp: stat.mtime };
2200 + } else if (FS.isFile(stat.mode)) {
2201 + files[path] = { contents: node.contents, mode: stat.mode, timestamp: stat.mtime };
2202 + } else {
2203 + return callback(new Error('node type not supported'));
2204 + }
2205 + }
2206 +
2207 + return callback(null, { type: 'local', files: files });
2208 + },getDB:function (name, callback) {
2209 + // look it up in the cache
2210 + var db = IDBFS.dbs[name];
2211 + if (db) {
2212 + return callback(null, db);
2213 + }
2214 + var req;
2215 + try {
2216 + req = IDBFS.indexedDB().open(name, IDBFS.DB_VERSION);
2217 + } catch (e) {
2218 + return onerror(e);
2219 + }
2220 + req.onupgradeneeded = function req_onupgradeneeded() {
2221 + db = req.result;
2222 + db.createObjectStore(IDBFS.DB_STORE_NAME);
2223 + };
2224 + req.onsuccess = function req_onsuccess() {
2225 + db = req.result;
2226 + // add to the cache
2227 + IDBFS.dbs[name] = db;
2228 + callback(null, db);
2229 + };
2230 + req.onerror = function req_onerror() {
2231 + callback(this.error);
2232 + };
2233 + },getRemoteSet:function (mount, callback) {
2234 + var files = {};
2235 +
2236 + IDBFS.getDB(mount.mountpoint, function(err, db) {
2237 + if (err) return callback(err);
2238 +
2239 + var transaction = db.transaction([IDBFS.DB_STORE_NAME], 'readonly');
2240 + transaction.onerror = function transaction_onerror() { callback(this.error); };
2241 +
2242 + var store = transaction.objectStore(IDBFS.DB_STORE_NAME);
2243 + store.openCursor().onsuccess = function store_openCursor_onsuccess(event) {
2244 + var cursor = event.target.result;
2245 + if (!cursor) {
2246 + return callback(null, { type: 'remote', db: db, files: files });
2247 + }
2248 +
2249 + files[cursor.key] = cursor.value;
2250 + cursor.continue();
2251 + };
2252 + });
2253 + }};
2254 +
2255 + var NODEFS={isWindows:false,staticInit:function () {
2256 + NODEFS.isWindows = !!process.platform.match(/^win/);
2257 + },mount:function (mount) {
2258 + assert(ENVIRONMENT_IS_NODE);
2259 + return NODEFS.createNode(null, '/', NODEFS.getMode(mount.opts.root), 0);
2260 + },createNode:function (parent, name, mode, dev) {
2261 + if (!FS.isDir(mode) && !FS.isFile(mode) && !FS.isLink(mode)) {
2262 + throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
2263 + }
2264 + var node = FS.createNode(parent, name, mode);
2265 + node.node_ops = NODEFS.node_ops;
2266 + node.stream_ops = NODEFS.stream_ops;
2267 + return node;
2268 + },getMode:function (path) {
2269 + var stat;
2270 + try {
2271 + stat = fs.lstatSync(path);
2272 + if (NODEFS.isWindows) {
2273 + // On Windows, directories return permission bits 'rw-rw-rw-', even though they have 'rwxrwxrwx', so
2274 + // propagate write bits to execute bits.
2275 + stat.mode = stat.mode | ((stat.mode & 146) >> 1);
2276 + }
2277 + } catch (e) {
2278 + if (!e.code) throw e;
2279 + throw new FS.ErrnoError(ERRNO_CODES[e.code]);
2280 + }
2281 + return stat.mode;
2282 + },realPath:function (node) {
2283 + var parts = [];
2284 + while (node.parent !== node) {
2285 + parts.push(node.name);
2286 + node = node.parent;
2287 + }
2288 + parts.push(node.mount.opts.root);
2289 + parts.reverse();
2290 + return PATH.join.apply(null, parts);
2291 + },flagsToPermissionStringMap:{0:"r",1:"r+",2:"r+",64:"r",65:"r+",66:"r+",129:"rx+",193:"rx+",514:"w+",577:"w",578:"w+",705:"wx",706:"wx+",1024:"a",1025:"a",1026:"a+",1089:"a",1090:"a+",1153:"ax",1154:"ax+",1217:"ax",1218:"ax+",4096:"rs",4098:"rs+"},flagsToPermissionString:function (flags) {
2292 + if (flags in NODEFS.flagsToPermissionStringMap) {
2293 + return NODEFS.flagsToPermissionStringMap[flags];
2294 + } else {
2295 + return flags;
2296 + }
2297 + },node_ops:{getattr:function (node) {
2298 + var path = NODEFS.realPath(node);
2299 + var stat;
2300 + try {
2301 + stat = fs.lstatSync(path);
2302 + } catch (e) {
2303 + if (!e.code) throw e;
2304 + throw new FS.ErrnoError(ERRNO_CODES[e.code]);
2305 + }
2306 + // node.js v0.10.20 doesn't report blksize and blocks on Windows. Fake them with default blksize of 4096.
2307 + // See http://support.microsoft.com/kb/140365
2308 + if (NODEFS.isWindows && !stat.blksize) {
2309 + stat.blksize = 4096;
2310 + }
2311 + if (NODEFS.isWindows && !stat.blocks) {
2312 + stat.blocks = (stat.size+stat.blksize-1)/stat.blksize|0;
2313 + }
2314 + return {
2315 + dev: stat.dev,
2316 + ino: stat.ino,
2317 + mode: stat.mode,
2318 + nlink: stat.nlink,
2319 + uid: stat.uid,
2320 + gid: stat.gid,
2321 + rdev: stat.rdev,
2322 + size: stat.size,
2323 + atime: stat.atime,
2324 + mtime: stat.mtime,
2325 + ctime: stat.ctime,
2326 + blksize: stat.blksize,
2327 + blocks: stat.blocks
2328 + };
2329 + },setattr:function (node, attr) {
2330 + var path = NODEFS.realPath(node);
2331 + try {
2332 + if (attr.mode !== undefined) {
2333 + fs.chmodSync(path, attr.mode);
2334 + // update the common node structure mode as well
2335 + node.mode = attr.mode;
2336 + }
2337 + if (attr.timestamp !== undefined) {
2338 + var date = new Date(attr.timestamp);
2339 + fs.utimesSync(path, date, date);
2340 + }
2341 + if (attr.size !== undefined) {
2342 + fs.truncateSync(path, attr.size);
2343 + }
2344 + } catch (e) {
2345 + if (!e.code) throw e;
2346 + throw new FS.ErrnoError(ERRNO_CODES[e.code]);
2347 + }
2348 + },lookup:function (parent, name) {
2349 + var path = PATH.join2(NODEFS.realPath(parent), name);
2350 + var mode = NODEFS.getMode(path);
2351 + return NODEFS.createNode(parent, name, mode);
2352 + },mknod:function (parent, name, mode, dev) {
2353 + var node = NODEFS.createNode(parent, name, mode, dev);
2354 + // create the backing node for this in the fs root as well
2355 + var path = NODEFS.realPath(node);
2356 + try {
2357 + if (FS.isDir(node.mode)) {
2358 + fs.mkdirSync(path, node.mode);
2359 + } else {
2360 + fs.writeFileSync(path, '', { mode: node.mode });
2361 + }
2362 + } catch (e) {
2363 + if (!e.code) throw e;
2364 + throw new FS.ErrnoError(ERRNO_CODES[e.code]);
2365 + }
2366 + return node;
2367 + },rename:function (oldNode, newDir, newName) {
2368 + var oldPath = NODEFS.realPath(oldNode);
2369 + var newPath = PATH.join2(NODEFS.realPath(newDir), newName);
2370 + try {
2371 + fs.renameSync(oldPath, newPath);
2372 + } catch (e) {
2373 + if (!e.code) throw e;
2374 + throw new FS.ErrnoError(ERRNO_CODES[e.code]);
2375 + }
2376 + },unlink:function (parent, name) {
2377 + var path = PATH.join2(NODEFS.realPath(parent), name);
2378 + try {
2379 + fs.unlinkSync(path);
2380 + } catch (e) {
2381 + if (!e.code) throw e;
2382 + throw new FS.ErrnoError(ERRNO_CODES[e.code]);
2383 + }
2384 + },rmdir:function (parent, name) {
2385 + var path = PATH.join2(NODEFS.realPath(parent), name);
2386 + try {
2387 + fs.rmdirSync(path);
2388 + } catch (e) {
2389 + if (!e.code) throw e;
2390 + throw new FS.ErrnoError(ERRNO_CODES[e.code]);
2391 + }
2392 + },readdir:function (node) {
2393 + var path = NODEFS.realPath(node);
2394 + try {
2395 + return fs.readdirSync(path);
2396 + } catch (e) {
2397 + if (!e.code) throw e;
2398 + throw new FS.ErrnoError(ERRNO_CODES[e.code]);
2399 + }
2400 + },symlink:function (parent, newName, oldPath) {
2401 + var newPath = PATH.join2(NODEFS.realPath(parent), newName);
2402 + try {
2403 + fs.symlinkSync(oldPath, newPath);
2404 + } catch (e) {
2405 + if (!e.code) throw e;
2406 + throw new FS.ErrnoError(ERRNO_CODES[e.code]);
2407 + }
2408 + },readlink:function (node) {
2409 + var path = NODEFS.realPath(node);
2410 + try {
2411 + return fs.readlinkSync(path);
2412 + } catch (e) {
2413 + if (!e.code) throw e;
2414 + throw new FS.ErrnoError(ERRNO_CODES[e.code]);
2415 + }
2416 + }},stream_ops:{open:function (stream) {
2417 + var path = NODEFS.realPath(stream.node);
2418 + try {
2419 + if (FS.isFile(stream.node.mode)) {
2420 + stream.nfd = fs.openSync(path, NODEFS.flagsToPermissionString(stream.flags));
2421 + }
2422 + } catch (e) {
2423 + if (!e.code) throw e;
2424 + throw new FS.ErrnoError(ERRNO_CODES[e.code]);
2425 + }
2426 + },close:function (stream) {
2427 + try {
2428 + if (FS.isFile(stream.node.mode) && stream.nfd) {
2429 + fs.closeSync(stream.nfd);
2430 + }
2431 + } catch (e) {
2432 + if (!e.code) throw e;
2433 + throw new FS.ErrnoError(ERRNO_CODES[e.code]);
2434 + }
2435 + },read:function (stream, buffer, offset, length, position) {
2436 + // FIXME this is terrible.
2437 + var nbuffer = Buffer.alloc(length);
2438 + var res;
2439 + try {
2440 + res = fs.readSync(stream.nfd, nbuffer, 0, length, position);
2441 + } catch (e) {
2442 + throw new FS.ErrnoError(ERRNO_CODES[e.code]);
2443 + }
2444 + if (res > 0) {
2445 + for (var i = 0; i < res; i++) {
2446 + buffer[offset + i] = nbuffer[i];
2447 + }
2448 + }
2449 + return res;
2450 + },write:function (stream, buffer, offset, length, position) {
2451 + // FIXME this is terrible.
2452 + var nbuffer = Buffer.alloc(buffer.subarray(offset, offset + length));
2453 + var res;
2454 + try {
2455 + res = fs.writeSync(stream.nfd, nbuffer, 0, length, position);
2456 + } catch (e) {
2457 + throw new FS.ErrnoError(ERRNO_CODES[e.code]);
2458 + }
2459 + return res;
2460 + },llseek:function (stream, offset, whence) {
2461 + var position = offset;
2462 + if (whence === 1) { // SEEK_CUR.
2463 + position += stream.position;
2464 + } else if (whence === 2) { // SEEK_END.
2465 + if (FS.isFile(stream.node.mode)) {
2466 + try {
2467 + var stat = fs.fstatSync(stream.nfd);
2468 + position += stat.size;
2469 + } catch (e) {
2470 + throw new FS.ErrnoError(ERRNO_CODES[e.code]);
2471 + }
2472 + }
2473 + }
2474 +
2475 + if (position < 0) {
2476 + throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
2477 + }
2478 +
2479 + stream.position = position;
2480 + return position;
2481 + }}};
2482 +
2483 + var _stdin=allocate(1, "i32*", ALLOC_STATIC);
2484 +
2485 + var _stdout=allocate(1, "i32*", ALLOC_STATIC);
2486 +
2487 + var _stderr=allocate(1, "i32*", ALLOC_STATIC);
2488 +
2489 + function _fflush(stream) {
2490 + // int fflush(FILE *stream);
2491 + // http://pubs.opengroup.org/onlinepubs/000095399/functions/fflush.html
2492 + // we don't currently perform any user-space buffering of data
2493 + }var FS={root:null,mounts:[],devices:[null],streams:[null],nextInode:1,nameTable:null,currentPath:"/",initialized:false,ignorePermissions:true,ErrnoError:null,genericErrors:{},handleFSError:function (e) {
2494 + if (!(e instanceof FS.ErrnoError)) throw e + ' : ' + stackTrace();
2495 + return ___setErrNo(e.errno);
2496 + },lookupPath:function (path, opts) {
2497 + path = PATH.resolve(FS.cwd(), path);
2498 + opts = opts || { recurse_count: 0 };
2499 +
2500 + if (opts.recurse_count > 8) { // max recursive lookup of 8
2501 + throw new FS.ErrnoError(ERRNO_CODES.ELOOP);
2502 + }
2503 +
2504 + // split the path
2505 + var parts = PATH.normalizeArray(path.split('/').filter(function(p) {
2506 + return !!p;
2507 + }), false);
2508 +
2509 + // start at the root
2510 + var current = FS.root;
2511 + var current_path = '/';
2512 +
2513 + for (var i = 0; i < parts.length; i++) {
2514 + var islast = (i === parts.length-1);
2515 + if (islast && opts.parent) {
2516 + // stop resolving
2517 + break;
2518 + }
2519 +
2520 + current = FS.lookupNode(current, parts[i]);
2521 + current_path = PATH.join2(current_path, parts[i]);
2522 +
2523 + // jump to the mount's root node if this is a mountpoint
2524 + if (FS.isMountpoint(current)) {
2525 + current = current.mount.root;
2526 + }
2527 +
2528 + // follow symlinks
2529 + // by default, lookupPath will not follow a symlink if it is the final path component.
2530 + // setting opts.follow = true will override this behavior.
2531 + if (!islast || opts.follow) {
2532 + var count = 0;
2533 + while (FS.isLink(current.mode)) {
2534 + var link = FS.readlink(current_path);
2535 + current_path = PATH.resolve(PATH.dirname(current_path), link);
2536 +
2537 + var lookup = FS.lookupPath(current_path, { recurse_count: opts.recurse_count });
2538 + current = lookup.node;
2539 +
2540 + if (count++ > 40) { // limit max consecutive symlinks to 40 (SYMLOOP_MAX).
2541 + throw new FS.ErrnoError(ERRNO_CODES.ELOOP);
2542 + }
2543 + }
2544 + }
2545 + }
2546 +
2547 + return { path: current_path, node: current };
2548 + },getPath:function (node) {
2549 + var path;
2550 + while (true) {
2551 + if (FS.isRoot(node)) {
2552 + var mount = node.mount.mountpoint;
2553 + if (!path) return mount;
2554 + return mount[mount.length-1] !== '/' ? mount + '/' + path : mount + path;
2555 + }
2556 + path = path ? node.name + '/' + path : node.name;
2557 + node = node.parent;
2558 + }
2559 + },hashName:function (parentid, name) {
2560 + var hash = 0;
2561 +
2562 +
2563 + for (var i = 0; i < name.length; i++) {
2564 + hash = ((hash << 5) - hash + name.charCodeAt(i)) | 0;
2565 + }
2566 + return ((parentid + hash) >>> 0) % FS.nameTable.length;
2567 + },hashAddNode:function (node) {
2568 + var hash = FS.hashName(node.parent.id, node.name);
2569 + node.name_next = FS.nameTable[hash];
2570 + FS.nameTable[hash] = node;
2571 + },hashRemoveNode:function (node) {
2572 + var hash = FS.hashName(node.parent.id, node.name);
2573 + if (FS.nameTable[hash] === node) {
2574 + FS.nameTable[hash] = node.name_next;
2575 + } else {
2576 + var current = FS.nameTable[hash];
2577 + while (current) {
2578 + if (current.name_next === node) {
2579 + current.name_next = node.name_next;
2580 + break;
2581 + }
2582 + current = current.name_next;
2583 + }
2584 + }
2585 + },lookupNode:function (parent, name) {
2586 + var err = FS.mayLookup(parent);
2587 + if (err) {
2588 + throw new FS.ErrnoError(err);
2589 + }
2590 + var hash = FS.hashName(parent.id, name);
2591 + for (var node = FS.nameTable[hash]; node; node = node.name_next) {
2592 + var nodeName = node.name;
2593 + if (node.parent.id === parent.id && nodeName === name) {
2594 + return node;
2595 + }
2596 + }
2597 + // if we failed to find it in the cache, call into the VFS
2598 + return FS.lookup(parent, name);
2599 + },createNode:function (parent, name, mode, rdev) {
2600 + if (!FS.FSNode) {
2601 + FS.FSNode = function(parent, name, mode, rdev) {
2602 + this.id = FS.nextInode++;
2603 + this.name = name;
2604 + this.mode = mode;
2605 + this.node_ops = {};
2606 + this.stream_ops = {};
2607 + this.rdev = rdev;
2608 + this.parent = null;
2609 + this.mount = null;
2610 + if (!parent) {
2611 + parent = this; // root node sets parent to itself
2612 + }
2613 + this.parent = parent;
2614 + this.mount = parent.mount;
2615 + FS.hashAddNode(this);
2616 + };
2617 +
2618 + // compatibility
2619 + var readMode = 292 | 73;
2620 + var writeMode = 146;
2621 +
2622 + FS.FSNode.prototype = {};
2623 +
2624 + // NOTE we must use Object.defineProperties instead of individual calls to
2625 + // Object.defineProperty in order to make closure compiler happy
2626 + Object.defineProperties(FS.FSNode.prototype, {
2627 + read: {
2628 + get: function() { return (this.mode & readMode) === readMode; },
2629 + set: function(val) { val ? this.mode |= readMode : this.mode &= ~readMode; }
2630 + },
2631 + write: {
2632 + get: function() { return (this.mode & writeMode) === writeMode; },
2633 + set: function(val) { val ? this.mode |= writeMode : this.mode &= ~writeMode; }
2634 + },
2635 + isFolder: {
2636 + get: function() { return FS.isDir(this.mode); },
2637 + },
2638 + isDevice: {
2639 + get: function() { return FS.isChrdev(this.mode); },
2640 + },
2641 + });
2642 + }
2643 + return new FS.FSNode(parent, name, mode, rdev);
2644 + },destroyNode:function (node) {
2645 + FS.hashRemoveNode(node);
2646 + },isRoot:function (node) {
2647 + return node === node.parent;
2648 + },isMountpoint:function (node) {
2649 + return node.mounted;
2650 + },isFile:function (mode) {
2651 + return (mode & 61440) === 32768;
2652 + },isDir:function (mode) {
2653 + return (mode & 61440) === 16384;
2654 + },isLink:function (mode) {
2655 + return (mode & 61440) === 40960;
2656 + },isChrdev:function (mode) {
2657 + return (mode & 61440) === 8192;
2658 + },isBlkdev:function (mode) {
2659 + return (mode & 61440) === 24576;
2660 + },isFIFO:function (mode) {
2661 + return (mode & 61440) === 4096;
2662 + },isSocket:function (mode) {
2663 + return (mode & 49152) === 49152;
2664 + },flagModes:{"r":0,"rs":1052672,"r+":2,"w":577,"wx":705,"xw":705,"w+":578,"wx+":706,"xw+":706,"a":1089,"ax":1217,"xa":1217,"a+":1090,"ax+":1218,"xa+":1218},modeStringToFlags:function (str) {
2665 + var flags = FS.flagModes[str];
2666 + if (typeof flags === 'undefined') {
2667 + throw new Error('Unknown file open mode: ' + str);
2668 + }
2669 + return flags;
2670 + },flagsToPermissionString:function (flag) {
2671 + var accmode = flag & 2097155;
2672 + var perms = ['r', 'w', 'rw'][accmode];
2673 + if ((flag & 512)) {
2674 + perms += 'w';
2675 + }
2676 + return perms;
2677 + },nodePermissions:function (node, perms) {
2678 + if (FS.ignorePermissions) {
2679 + return 0;
2680 + }
2681 + // return 0 if any user, group or owner bits are set.
2682 + if (perms.indexOf('r') !== -1 && !(node.mode & 292)) {
2683 + return ERRNO_CODES.EACCES;
2684 + } else if (perms.indexOf('w') !== -1 && !(node.mode & 146)) {
2685 + return ERRNO_CODES.EACCES;
2686 + } else if (perms.indexOf('x') !== -1 && !(node.mode & 73)) {
2687 + return ERRNO_CODES.EACCES;
2688 + }
2689 + return 0;
2690 + },mayLookup:function (dir) {
2691 + return FS.nodePermissions(dir, 'x');
2692 + },mayCreate:function (dir, name) {
2693 + try {
2694 + var node = FS.lookupNode(dir, name);
2695 + return ERRNO_CODES.EEXIST;
2696 + } catch (e) {
2697 + }
2698 + return FS.nodePermissions(dir, 'wx');
2699 + },mayDelete:function (dir, name, isdir) {
2700 + var node;
2701 + try {
2702 + node = FS.lookupNode(dir, name);
2703 + } catch (e) {
2704 + return e.errno;
2705 + }
2706 + var err = FS.nodePermissions(dir, 'wx');
2707 + if (err) {
2708 + return err;
2709 + }
2710 + if (isdir) {
2711 + if (!FS.isDir(node.mode)) {
2712 + return ERRNO_CODES.ENOTDIR;
2713 + }
2714 + if (FS.isRoot(node) || FS.getPath(node) === FS.cwd()) {
2715 + return ERRNO_CODES.EBUSY;
2716 + }
2717 + } else {
2718 + if (FS.isDir(node.mode)) {
2719 + return ERRNO_CODES.EISDIR;
2720 + }
2721 + }
2722 + return 0;
2723 + },mayOpen:function (node, flags) {
2724 + if (!node) {
2725 + return ERRNO_CODES.ENOENT;
2726 + }
2727 + if (FS.isLink(node.mode)) {
2728 + return ERRNO_CODES.ELOOP;
2729 + } else if (FS.isDir(node.mode)) {
2730 + if ((flags & 2097155) !== 0 || // opening for write
2731 + (flags & 512)) {
2732 + return ERRNO_CODES.EISDIR;
2733 + }
2734 + }
2735 + return FS.nodePermissions(node, FS.flagsToPermissionString(flags));
2736 + },MAX_OPEN_FDS:4096,nextfd:function (fd_start, fd_end) {
2737 + fd_start = fd_start || 1;
2738 + fd_end = fd_end || FS.MAX_OPEN_FDS;
2739 + for (var fd = fd_start; fd <= fd_end; fd++) {
2740 + if (!FS.streams[fd]) {
2741 + return fd;
2742 + }
2743 + }
2744 + throw new FS.ErrnoError(ERRNO_CODES.EMFILE);
2745 + },getStream:function (fd) {
2746 + return FS.streams[fd];
2747 + },createStream:function (stream, fd_start, fd_end) {
2748 + if (!FS.FSStream) {
2749 + FS.FSStream = function(){};
2750 + FS.FSStream.prototype = {};
2751 + // compatibility
2752 + Object.defineProperties(FS.FSStream.prototype, {
2753 + object: {
2754 + get: function() { return this.node; },
2755 + set: function(val) { this.node = val; }
2756 + },
2757 + isRead: {
2758 + get: function() { return (this.flags & 2097155) !== 1; }
2759 + },
2760 + isWrite: {
2761 + get: function() { return (this.flags & 2097155) !== 0; }
2762 + },
2763 + isAppend: {
2764 + get: function() { return (this.flags & 1024); }
2765 + }
2766 + });
2767 + }
2768 + if (stream.__proto__) {
2769 + // reuse the object
2770 + stream.__proto__ = FS.FSStream.prototype;
2771 + } else {
2772 + var newStream = new FS.FSStream();
2773 + for (var p in stream) {
2774 + newStream[p] = stream[p];
2775 + }
2776 + stream = newStream;
2777 + }
2778 + var fd = FS.nextfd(fd_start, fd_end);
2779 + stream.fd = fd;
2780 + FS.streams[fd] = stream;
2781 + return stream;
2782 + },closeStream:function (fd) {
2783 + FS.streams[fd] = null;
2784 + },chrdev_stream_ops:{open:function (stream) {
2785 + var device = FS.getDevice(stream.node.rdev);
2786 + // override node's stream ops with the device's
2787 + stream.stream_ops = device.stream_ops;
2788 + // forward the open call
2789 + if (stream.stream_ops.open) {
2790 + stream.stream_ops.open(stream);
2791 + }
2792 + },llseek:function () {
2793 + throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
2794 + }},major:function (dev) {
2795 + return ((dev) >> 8);
2796 + },minor:function (dev) {
2797 + return ((dev) & 0xff);
2798 + },makedev:function (ma, mi) {
2799 + return ((ma) << 8 | (mi));
2800 + },registerDevice:function (dev, ops) {
2801 + FS.devices[dev] = { stream_ops: ops };
2802 + },getDevice:function (dev) {
2803 + return FS.devices[dev];
2804 + },syncfs:function (populate, callback) {
2805 + if (typeof(populate) === 'function') {
2806 + callback = populate;
2807 + populate = false;
2808 + }
2809 +
2810 + var completed = 0;
2811 + var total = FS.mounts.length;
2812 + function done(err) {
2813 + if (err) {
2814 + return callback(err);
2815 + }
2816 + if (++completed >= total) {
2817 + callback(null);
2818 + }
2819 + };
2820 +
2821 + // sync all mounts
2822 + for (var i = 0; i < FS.mounts.length; i++) {
2823 + var mount = FS.mounts[i];
2824 + if (!mount.type.syncfs) {
2825 + done(null);
2826 + continue;
2827 + }
2828 + mount.type.syncfs(mount, populate, done);
2829 + }
2830 + },mount:function (type, opts, mountpoint) {
2831 + var lookup;
2832 + if (mountpoint) {
2833 + lookup = FS.lookupPath(mountpoint, { follow: false });
2834 + mountpoint = lookup.path; // use the absolute path
2835 + }
2836 + var mount = {
2837 + type: type,
2838 + opts: opts,
2839 + mountpoint: mountpoint,
2840 + root: null
2841 + };
2842 + // create a root node for the fs
2843 + var root = type.mount(mount);
2844 + root.mount = mount;
2845 + mount.root = root;
2846 + // assign the mount info to the mountpoint's node
2847 + if (lookup) {
2848 + lookup.node.mount = mount;
2849 + lookup.node.mounted = true;
2850 + // compatibility update FS.root if we mount to /
2851 + if (mountpoint === '/') {
2852 + FS.root = mount.root;
2853 + }
2854 + }
2855 + // add to our cached list of mounts
2856 + FS.mounts.push(mount);
2857 + return root;
2858 + },lookup:function (parent, name) {
2859 + return parent.node_ops.lookup(parent, name);
2860 + },mknod:function (path, mode, dev) {
2861 + var lookup = FS.lookupPath(path, { parent: true });
2862 + var parent = lookup.node;
2863 + var name = PATH.basename(path);
2864 + var err = FS.mayCreate(parent, name);
2865 + if (err) {
2866 + throw new FS.ErrnoError(err);
2867 + }
2868 + if (!parent.node_ops.mknod) {
2869 + throw new FS.ErrnoError(ERRNO_CODES.EPERM);
2870 + }
2871 + return parent.node_ops.mknod(parent, name, mode, dev);
2872 + },create:function (path, mode) {
2873 + mode = mode !== undefined ? mode : 0666;
2874 + mode &= 4095;
2875 + mode |= 32768;
2876 + return FS.mknod(path, mode, 0);
2877 + },mkdir:function (path, mode) {
2878 + mode = mode !== undefined ? mode : 0777;
2879 + mode &= 511 | 512;
2880 + mode |= 16384;
2881 + return FS.mknod(path, mode, 0);
2882 + },mkdev:function (path, mode, dev) {
2883 + if (typeof(dev) === 'undefined') {
2884 + dev = mode;
2885 + mode = 0666;
2886 + }
2887 + mode |= 8192;
2888 + return FS.mknod(path, mode, dev);
2889 + },symlink:function (oldpath, newpath) {
2890 + var lookup = FS.lookupPath(newpath, { parent: true });
2891 + var parent = lookup.node;
2892 + var newname = PATH.basename(newpath);
2893 + var err = FS.mayCreate(parent, newname);
2894 + if (err) {
2895 + throw new FS.ErrnoError(err);
2896 + }
2897 + if (!parent.node_ops.symlink) {
2898 + throw new FS.ErrnoError(ERRNO_CODES.EPERM);
2899 + }
2900 + return parent.node_ops.symlink(parent, newname, oldpath);
2901 + },rename:function (old_path, new_path) {
2902 + var old_dirname = PATH.dirname(old_path);
2903 + var new_dirname = PATH.dirname(new_path);
2904 + var old_name = PATH.basename(old_path);
2905 + var new_name = PATH.basename(new_path);
2906 + // parents must exist
2907 + var lookup, old_dir, new_dir;
2908 + try {
2909 + lookup = FS.lookupPath(old_path, { parent: true });
2910 + old_dir = lookup.node;
2911 + lookup = FS.lookupPath(new_path, { parent: true });
2912 + new_dir = lookup.node;
2913 + } catch (e) {
2914 + throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
2915 + }
2916 + // need to be part of the same mount
2917 + if (old_dir.mount !== new_dir.mount) {
2918 + throw new FS.ErrnoError(ERRNO_CODES.EXDEV);
2919 + }
2920 + // source must exist
2921 + var old_node = FS.lookupNode(old_dir, old_name);
2922 + // old path should not be an ancestor of the new path
2923 + var relative = PATH.relative(old_path, new_dirname);
2924 + if (relative.charAt(0) !== '.') {
2925 + throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
2926 + }
2927 + // new path should not be an ancestor of the old path
2928 + relative = PATH.relative(new_path, old_dirname);
2929 + if (relative.charAt(0) !== '.') {
2930 + throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY);
2931 + }
2932 + // see if the new path already exists
2933 + var new_node;
2934 + try {
2935 + new_node = FS.lookupNode(new_dir, new_name);
2936 + } catch (e) {
2937 + // not fatal
2938 + }
2939 + // early out if nothing needs to change
2940 + if (old_node === new_node) {
2941 + return;
2942 + }
2943 + // we'll need to delete the old entry
2944 + var isdir = FS.isDir(old_node.mode);
2945 + var err = FS.mayDelete(old_dir, old_name, isdir);
2946 + if (err) {
2947 + throw new FS.ErrnoError(err);
2948 + }
2949 + // need delete permissions if we'll be overwriting.
2950 + // need create permissions if new doesn't already exist.
2951 + err = new_node ?
2952 + FS.mayDelete(new_dir, new_name, isdir) :
2953 + FS.mayCreate(new_dir, new_name);
2954 + if (err) {
2955 + throw new FS.ErrnoError(err);
2956 + }
2957 + if (!old_dir.node_ops.rename) {
2958 + throw new FS.ErrnoError(ERRNO_CODES.EPERM);
2959 + }
2960 + if (FS.isMountpoint(old_node) || (new_node && FS.isMountpoint(new_node))) {
2961 + throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
2962 + }
2963 + // if we are going to change the parent, check write permissions
2964 + if (new_dir !== old_dir) {
2965 + err = FS.nodePermissions(old_dir, 'w');
2966 + if (err) {
2967 + throw new FS.ErrnoError(err);
2968 + }
2969 + }
2970 + // remove the node from the lookup hash
2971 + FS.hashRemoveNode(old_node);
2972 + // do the underlying fs rename
2973 + try {
2974 + old_dir.node_ops.rename(old_node, new_dir, new_name);
2975 + } catch (e) {
2976 + throw e;
2977 + } finally {
2978 + // add the node back to the hash (in case node_ops.rename
2979 + // changed its name)
2980 + FS.hashAddNode(old_node);
2981 + }
2982 + },rmdir:function (path) {
2983 + var lookup = FS.lookupPath(path, { parent: true });
2984 + var parent = lookup.node;
2985 + var name = PATH.basename(path);
2986 + var node = FS.lookupNode(parent, name);
2987 + var err = FS.mayDelete(parent, name, true);
2988 + if (err) {
2989 + throw new FS.ErrnoError(err);
2990 + }
2991 + if (!parent.node_ops.rmdir) {
2992 + throw new FS.ErrnoError(ERRNO_CODES.EPERM);
2993 + }
2994 + if (FS.isMountpoint(node)) {
2995 + throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
2996 + }
2997 + parent.node_ops.rmdir(parent, name);
2998 + FS.destroyNode(node);
2999 + },readdir:function (path) {
3000 + var lookup = FS.lookupPath(path, { follow: true });
3001 + var node = lookup.node;
3002 + if (!node.node_ops.readdir) {
3003 + throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR);
3004 + }
3005 + return node.node_ops.readdir(node);
3006 + },unlink:function (path) {
3007 + var lookup = FS.lookupPath(path, { parent: true });
3008 + var parent = lookup.node;
3009 + var name = PATH.basename(path);
3010 + var node = FS.lookupNode(parent, name);
3011 + var err = FS.mayDelete(parent, name, false);
3012 + if (err) {
3013 + // POSIX says unlink should set EPERM, not EISDIR
3014 + if (err === ERRNO_CODES.EISDIR) err = ERRNO_CODES.EPERM;
3015 + throw new FS.ErrnoError(err);
3016 + }
3017 + if (!parent.node_ops.unlink) {
3018 + throw new FS.ErrnoError(ERRNO_CODES.EPERM);
3019 + }
3020 + if (FS.isMountpoint(node)) {
3021 + throw new FS.ErrnoError(ERRNO_CODES.EBUSY);
3022 + }
3023 + parent.node_ops.unlink(parent, name);
3024 + FS.destroyNode(node);
3025 + },readlink:function (path) {
3026 + var lookup = FS.lookupPath(path, { follow: false });
3027 + var link = lookup.node;
3028 + if (!link.node_ops.readlink) {
3029 + throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
3030 + }
3031 + return link.node_ops.readlink(link);
3032 + },stat:function (path, dontFollow) {
3033 + var lookup = FS.lookupPath(path, { follow: !dontFollow });
3034 + var node = lookup.node;
3035 + if (!node.node_ops.getattr) {
3036 + throw new FS.ErrnoError(ERRNO_CODES.EPERM);
3037 + }
3038 + return node.node_ops.getattr(node);
3039 + },lstat:function (path) {
3040 + return FS.stat(path, true);
3041 + },chmod:function (path, mode, dontFollow) {
3042 + var node;
3043 + if (typeof path === 'string') {
3044 + var lookup = FS.lookupPath(path, { follow: !dontFollow });
3045 + node = lookup.node;
3046 + } else {
3047 + node = path;
3048 + }
3049 + if (!node.node_ops.setattr) {
3050 + throw new FS.ErrnoError(ERRNO_CODES.EPERM);
3051 + }
3052 + node.node_ops.setattr(node, {
3053 + mode: (mode & 4095) | (node.mode & ~4095),
3054 + timestamp: Date.now()
3055 + });
3056 + },lchmod:function (path, mode) {
3057 + FS.chmod(path, mode, true);
3058 + },fchmod:function (fd, mode) {
3059 + var stream = FS.getStream(fd);
3060 + if (!stream) {
3061 + throw new FS.ErrnoError(ERRNO_CODES.EBADF);
3062 + }
3063 + FS.chmod(stream.node, mode);
3064 + },chown:function (path, uid, gid, dontFollow) {
3065 + var node;
3066 + if (typeof path === 'string') {
3067 + var lookup = FS.lookupPath(path, { follow: !dontFollow });
3068 + node = lookup.node;
3069 + } else {
3070 + node = path;
3071 + }
3072 + if (!node.node_ops.setattr) {
3073 + throw new FS.ErrnoError(ERRNO_CODES.EPERM);
3074 + }
3075 + node.node_ops.setattr(node, {
3076 + timestamp: Date.now()
3077 + // we ignore the uid / gid for now
3078 + });
3079 + },lchown:function (path, uid, gid) {
3080 + FS.chown(path, uid, gid, true);
3081 + },fchown:function (fd, uid, gid) {
3082 + var stream = FS.getStream(fd);
3083 + if (!stream) {
3084 + throw new FS.ErrnoError(ERRNO_CODES.EBADF);
3085 + }
3086 + FS.chown(stream.node, uid, gid);
3087 + },truncate:function (path, len) {
3088 + if (len < 0) {
3089 + throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
3090 + }
3091 + var node;
3092 + if (typeof path === 'string') {
3093 + var lookup = FS.lookupPath(path, { follow: true });
3094 + node = lookup.node;
3095 + } else {
3096 + node = path;
3097 + }
3098 + if (!node.node_ops.setattr) {
3099 + throw new FS.ErrnoError(ERRNO_CODES.EPERM);
3100 + }
3101 + if (FS.isDir(node.mode)) {
3102 + throw new FS.ErrnoError(ERRNO_CODES.EISDIR);
3103 + }
3104 + if (!FS.isFile(node.mode)) {
3105 + throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
3106 + }
3107 + var err = FS.nodePermissions(node, 'w');
3108 + if (err) {
3109 + throw new FS.ErrnoError(err);
3110 + }
3111 + node.node_ops.setattr(node, {
3112 + size: len,
3113 + timestamp: Date.now()
3114 + });
3115 + },ftruncate:function (fd, len) {
3116 + var stream = FS.getStream(fd);
3117 + if (!stream) {
3118 + throw new FS.ErrnoError(ERRNO_CODES.EBADF);
3119 + }
3120 + if ((stream.flags & 2097155) === 0) {
3121 + throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
3122 + }
3123 + FS.truncate(stream.node, len);
3124 + },utime:function (path, atime, mtime) {
3125 + var lookup = FS.lookupPath(path, { follow: true });
3126 + var node = lookup.node;
3127 + node.node_ops.setattr(node, {
3128 + timestamp: Math.max(atime, mtime)
3129 + });
3130 + },open:function (path, flags, mode, fd_start, fd_end) {
3131 + flags = typeof flags === 'string' ? FS.modeStringToFlags(flags) : flags;
3132 + mode = typeof mode === 'undefined' ? 0666 : mode;
3133 + if ((flags & 64)) {
3134 + mode = (mode & 4095) | 32768;
3135 + } else {
3136 + mode = 0;
3137 + }
3138 + var node;
3139 + if (typeof path === 'object') {
3140 + node = path;
3141 + } else {
3142 + path = PATH.normalize(path);
3143 + try {
3144 + var lookup = FS.lookupPath(path, {
3145 + follow: !(flags & 131072)
3146 + });
3147 + node = lookup.node;
3148 + } catch (e) {
3149 + // ignore
3150 + }
3151 + }
3152 + // perhaps we need to create the node
3153 + if ((flags & 64)) {
3154 + if (node) {
3155 + // if O_CREAT and O_EXCL are set, error out if the node already exists
3156 + if ((flags & 128)) {
3157 + throw new FS.ErrnoError(ERRNO_CODES.EEXIST);
3158 + }
3159 + } else {
3160 + // node doesn't exist, try to create it
3161 + node = FS.mknod(path, mode, 0);
3162 + }
3163 + }
3164 + if (!node) {
3165 + throw new FS.ErrnoError(ERRNO_CODES.ENOENT);
3166 + }
3167 + // can't truncate a device
3168 + if (FS.isChrdev(node.mode)) {
3169 + flags &= ~512;
3170 + }
3171 + // check permissions
3172 + var err = FS.mayOpen(node, flags);
3173 + if (err) {
3174 + throw new FS.ErrnoError(err);
3175 + }
3176 + // do truncation if necessary
3177 + if ((flags & 512)) {
3178 + FS.truncate(node, 0);
3179 + }
3180 + // we've already handled these, don't pass down to the underlying vfs
3181 + flags &= ~(128 | 512);
3182 +
3183 + // register the stream with the filesystem
3184 + var stream = FS.createStream({
3185 + node: node,
3186 + path: FS.getPath(node), // we want the absolute path to the node
3187 + flags: flags,
3188 + seekable: true,
3189 + position: 0,
3190 + stream_ops: node.stream_ops,
3191 + // used by the file family libc calls (fopen, fwrite, ferror, etc.)
3192 + ungotten: [],
3193 + error: false
3194 + }, fd_start, fd_end);
3195 + // call the new stream's open function
3196 + if (stream.stream_ops.open) {
3197 + stream.stream_ops.open(stream);
3198 + }
3199 + if (Module['logReadFiles'] && !(flags & 1)) {
3200 + if (!FS.readFiles) FS.readFiles = {};
3201 + if (!(path in FS.readFiles)) {
3202 + FS.readFiles[path] = 1;
3203 + Module['printErr']('read file: ' + path);
3204 + }
3205 + }
3206 + return stream;
3207 + },close:function (stream) {
3208 + try {
3209 + if (stream.stream_ops.close) {
3210 + stream.stream_ops.close(stream);
3211 + }
3212 + } catch (e) {
3213 + throw e;
3214 + } finally {
3215 + FS.closeStream(stream.fd);
3216 + }
3217 + },llseek:function (stream, offset, whence) {
3218 + if (!stream.seekable || !stream.stream_ops.llseek) {
3219 + throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
3220 + }
3221 + return stream.stream_ops.llseek(stream, offset, whence);
3222 + },read:function (stream, buffer, offset, length, position) {
3223 + if (length < 0 || position < 0) {
3224 + throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
3225 + }
3226 + if ((stream.flags & 2097155) === 1) {
3227 + throw new FS.ErrnoError(ERRNO_CODES.EBADF);
3228 + }
3229 + if (FS.isDir(stream.node.mode)) {
3230 + throw new FS.ErrnoError(ERRNO_CODES.EISDIR);
3231 + }
3232 + if (!stream.stream_ops.read) {
3233 + throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
3234 + }
3235 + var seeking = true;
3236 + if (typeof position === 'undefined') {
3237 + position = stream.position;
3238 + seeking = false;
3239 + } else if (!stream.seekable) {
3240 + throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
3241 + }
3242 + var bytesRead = stream.stream_ops.read(stream, buffer, offset, length, position);
3243 + if (!seeking) stream.position += bytesRead;
3244 + return bytesRead;
3245 + },write:function (stream, buffer, offset, length, position, canOwn) {
3246 + if (length < 0 || position < 0) {
3247 + throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
3248 + }
3249 + if ((stream.flags & 2097155) === 0) {
3250 + throw new FS.ErrnoError(ERRNO_CODES.EBADF);
3251 + }
3252 + if (FS.isDir(stream.node.mode)) {
3253 + throw new FS.ErrnoError(ERRNO_CODES.EISDIR);
3254 + }
3255 + if (!stream.stream_ops.write) {
3256 + throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
3257 + }
3258 + var seeking = true;
3259 + if (typeof position === 'undefined') {
3260 + position = stream.position;
3261 + seeking = false;
3262 + } else if (!stream.seekable) {
3263 + throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
3264 + }
3265 + if (stream.flags & 1024) {
3266 + // seek to the end before writing in append mode
3267 + FS.llseek(stream, 0, 2);
3268 + }
3269 + var bytesWritten = stream.stream_ops.write(stream, buffer, offset, length, position, canOwn);
3270 + if (!seeking) stream.position += bytesWritten;
3271 + return bytesWritten;
3272 + },allocate:function (stream, offset, length) {
3273 + if (offset < 0 || length <= 0) {
3274 + throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
3275 + }
3276 + if ((stream.flags & 2097155) === 0) {
3277 + throw new FS.ErrnoError(ERRNO_CODES.EBADF);
3278 + }
3279 + if (!FS.isFile(stream.node.mode) && !FS.isDir(node.mode)) {
3280 + throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
3281 + }
3282 + if (!stream.stream_ops.allocate) {
3283 + throw new FS.ErrnoError(ERRNO_CODES.EOPNOTSUPP);
3284 + }
3285 + stream.stream_ops.allocate(stream, offset, length);
3286 + },mmap:function (stream, buffer, offset, length, position, prot, flags) {
3287 + // TODO if PROT is PROT_WRITE, make sure we have write access
3288 + if ((stream.flags & 2097155) === 1) {
3289 + throw new FS.ErrnoError(ERRNO_CODES.EACCES);
3290 + }
3291 + if (!stream.stream_ops.mmap) {
3292 + throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
3293 + }
3294 + return stream.stream_ops.mmap(stream, buffer, offset, length, position, prot, flags);
3295 + },ioctl:function (stream, cmd, arg) {
3296 + if (!stream.stream_ops.ioctl) {
3297 + throw new FS.ErrnoError(ERRNO_CODES.ENOTTY);
3298 + }
3299 + return stream.stream_ops.ioctl(stream, cmd, arg);
3300 + },readFile:function (path, opts) {
3301 + opts = opts || {};
3302 + opts.flags = opts.flags || 'r';
3303 + opts.encoding = opts.encoding || 'binary';
3304 + var ret;
3305 + var stream = FS.open(path, opts.flags);
3306 + var stat = FS.stat(path);
3307 + var length = stat.size;
3308 + var buf = new Uint8Array(length);
3309 + FS.read(stream, buf, 0, length, 0);
3310 + if (opts.encoding === 'utf8') {
3311 + ret = '';
3312 + var utf8 = new Runtime.UTF8Processor();
3313 + for (var i = 0; i < length; i++) {
3314 + ret += utf8.processCChar(buf[i]);
3315 + }
3316 + } else if (opts.encoding === 'binary') {
3317 + ret = buf;
3318 + } else {
3319 + throw new Error('Invalid encoding type "' + opts.encoding + '"');
3320 + }
3321 + FS.close(stream);
3322 + return ret;
3323 + },writeFile:function (path, data, opts) {
3324 + opts = opts || {};
3325 + opts.flags = opts.flags || 'w';
3326 + opts.encoding = opts.encoding || 'utf8';
3327 + var stream = FS.open(path, opts.flags, opts.mode);
3328 + if (opts.encoding === 'utf8') {
3329 + var utf8 = new Runtime.UTF8Processor();
3330 + var buf = new Uint8Array(utf8.processJSString(data));
3331 + FS.write(stream, buf, 0, buf.length, 0);
3332 + } else if (opts.encoding === 'binary') {
3333 + FS.write(stream, data, 0, data.length, 0);
3334 + } else {
3335 + throw new Error('Invalid encoding type "' + opts.encoding + '"');
3336 + }
3337 + FS.close(stream);
3338 + },cwd:function () {
3339 + return FS.currentPath;
3340 + },chdir:function (path) {
3341 + var lookup = FS.lookupPath(path, { follow: true });
3342 + if (!FS.isDir(lookup.node.mode)) {
3343 + throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR);
3344 + }
3345 + var err = FS.nodePermissions(lookup.node, 'x');
3346 + if (err) {
3347 + throw new FS.ErrnoError(err);
3348 + }
3349 + FS.currentPath = lookup.path;
3350 + },createDefaultDirectories:function () {
3351 + FS.mkdir('/tmp');
3352 + },createDefaultDevices:function () {
3353 + // create /dev
3354 + FS.mkdir('/dev');
3355 + // setup /dev/null
3356 + FS.registerDevice(FS.makedev(1, 3), {
3357 + read: function() { return 0; },
3358 + write: function() { return 0; }
3359 + });
3360 + FS.mkdev('/dev/null', FS.makedev(1, 3));
3361 + // setup /dev/tty and /dev/tty1
3362 + // stderr needs to print output using Module['printErr']
3363 + // so we register a second tty just for it.
3364 + TTY.register(FS.makedev(5, 0), TTY.default_tty_ops);
3365 + TTY.register(FS.makedev(6, 0), TTY.default_tty1_ops);
3366 + FS.mkdev('/dev/tty', FS.makedev(5, 0));
3367 + FS.mkdev('/dev/tty1', FS.makedev(6, 0));
3368 + // we're not going to emulate the actual shm device,
3369 + // just create the tmp dirs that reside in it commonly
3370 + FS.mkdir('/dev/shm');
3371 + FS.mkdir('/dev/shm/tmp');
3372 + },createStandardStreams:function () {
3373 + // TODO deprecate the old functionality of a single
3374 + // input / output callback and that utilizes FS.createDevice
3375 + // and instead require a unique set of stream ops
3376 +
3377 + // by default, we symlink the standard streams to the
3378 + // default tty devices. however, if the standard streams
3379 + // have been overwritten we create a unique device for
3380 + // them instead.
3381 + if (Module['stdin']) {
3382 + FS.createDevice('/dev', 'stdin', Module['stdin']);
3383 + } else {
3384 + FS.symlink('/dev/tty', '/dev/stdin');
3385 + }
3386 + if (Module['stdout']) {
3387 + FS.createDevice('/dev', 'stdout', null, Module['stdout']);
3388 + } else {
3389 + FS.symlink('/dev/tty', '/dev/stdout');
3390 + }
3391 + if (Module['stderr']) {
3392 + FS.createDevice('/dev', 'stderr', null, Module['stderr']);
3393 + } else {
3394 + FS.symlink('/dev/tty1', '/dev/stderr');
3395 + }
3396 +
3397 + // open default streams for the stdin, stdout and stderr devices
3398 + var stdin = FS.open('/dev/stdin', 'r');
3399 + HEAP32[((_stdin)>>2)]=stdin.fd;
3400 + assert(stdin.fd === 1, 'invalid handle for stdin (' + stdin.fd + ')');
3401 +
3402 + var stdout = FS.open('/dev/stdout', 'w');
3403 + HEAP32[((_stdout)>>2)]=stdout.fd;
3404 + assert(stdout.fd === 2, 'invalid handle for stdout (' + stdout.fd + ')');
3405 +
3406 + var stderr = FS.open('/dev/stderr', 'w');
3407 + HEAP32[((_stderr)>>2)]=stderr.fd;
3408 + assert(stderr.fd === 3, 'invalid handle for stderr (' + stderr.fd + ')');
3409 + },ensureErrnoError:function () {
3410 + if (FS.ErrnoError) return;
3411 + FS.ErrnoError = function ErrnoError(errno) {
3412 + this.errno = errno;
3413 + for (var key in ERRNO_CODES) {
3414 + if (ERRNO_CODES[key] === errno) {
3415 + this.code = key;
3416 + break;
3417 + }
3418 + }
3419 + this.message = ERRNO_MESSAGES[errno];
3420 + if (this.stack) this.stack = demangleAll(this.stack);
3421 + };
3422 + FS.ErrnoError.prototype = new Error();
3423 + FS.ErrnoError.prototype.constructor = FS.ErrnoError;
3424 + // Some errors may happen quite a bit, to avoid overhead we reuse them (and suffer a lack of stack info)
3425 + [ERRNO_CODES.ENOENT].forEach(function(code) {
3426 + FS.genericErrors[code] = new FS.ErrnoError(code);
3427 + FS.genericErrors[code].stack = '<generic error, no stack>';
3428 + });
3429 + },staticInit:function () {
3430 + FS.ensureErrnoError();
3431 +
3432 + FS.nameTable = new Array(4096);
3433 +
3434 + FS.root = FS.createNode(null, '/', 16384 | 0777, 0);
3435 + FS.mount(MEMFS, {}, '/');
3436 +
3437 + FS.createDefaultDirectories();
3438 + FS.createDefaultDevices();
3439 + },init:function (input, output, error) {
3440 + assert(!FS.init.initialized, 'FS.init was previously called. If you want to initialize later with custom parameters, remove any earlier calls (note that one is automatically added to the generated code)');
3441 + FS.init.initialized = true;
3442 +
3443 + FS.ensureErrnoError();
3444 +
3445 + // Allow Module.stdin etc. to provide defaults, if none explicitly passed to us here
3446 + Module['stdin'] = input || Module['stdin'];
3447 + Module['stdout'] = output || Module['stdout'];
3448 + Module['stderr'] = error || Module['stderr'];
3449 +
3450 + FS.createStandardStreams();
3451 + },quit:function () {
3452 + FS.init.initialized = false;
3453 + for (var i = 0; i < FS.streams.length; i++) {
3454 + var stream = FS.streams[i];
3455 + if (!stream) {
3456 + continue;
3457 + }
3458 + FS.close(stream);
3459 + }
3460 + },getMode:function (canRead, canWrite) {
3461 + var mode = 0;
3462 + if (canRead) mode |= 292 | 73;
3463 + if (canWrite) mode |= 146;
3464 + return mode;
3465 + },joinPath:function (parts, forceRelative) {
3466 + var path = PATH.join.apply(null, parts);
3467 + if (forceRelative && path[0] == '/') path = path.substr(1);
3468 + return path;
3469 + },absolutePath:function (relative, base) {
3470 + return PATH.resolve(base, relative);
3471 + },standardizePath:function (path) {
3472 + return PATH.normalize(path);
3473 + },findObject:function (path, dontResolveLastLink) {
3474 + var ret = FS.analyzePath(path, dontResolveLastLink);
3475 + if (ret.exists) {
3476 + return ret.object;
3477 + } else {
3478 + ___setErrNo(ret.error);
3479 + return null;
3480 + }
3481 + },analyzePath:function (path, dontResolveLastLink) {
3482 + // operate from within the context of the symlink's target
3483 + try {
3484 + var lookup = FS.lookupPath(path, { follow: !dontResolveLastLink });
3485 + path = lookup.path;
3486 + } catch (e) {
3487 + }
3488 + var ret = {
3489 + isRoot: false, exists: false, error: 0, name: null, path: null, object: null,
3490 + parentExists: false, parentPath: null, parentObject: null
3491 + };
3492 + try {
3493 + var lookup = FS.lookupPath(path, { parent: true });
3494 + ret.parentExists = true;
3495 + ret.parentPath = lookup.path;
3496 + ret.parentObject = lookup.node;
3497 + ret.name = PATH.basename(path);
3498 + lookup = FS.lookupPath(path, { follow: !dontResolveLastLink });
3499 + ret.exists = true;
3500 + ret.path = lookup.path;
3501 + ret.object = lookup.node;
3502 + ret.name = lookup.node.name;
3503 + ret.isRoot = lookup.path === '/';
3504 + } catch (e) {
3505 + ret.error = e.errno;
3506 + };
3507 + return ret;
3508 + },createFolder:function (parent, name, canRead, canWrite) {
3509 + var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
3510 + var mode = FS.getMode(canRead, canWrite);
3511 + return FS.mkdir(path, mode);
3512 + },createPath:function (parent, path, canRead, canWrite) {
3513 + parent = typeof parent === 'string' ? parent : FS.getPath(parent);
3514 + var parts = path.split('/').reverse();
3515 + while (parts.length) {
3516 + var part = parts.pop();
3517 + if (!part) continue;
3518 + var current = PATH.join2(parent, part);
3519 + try {
3520 + FS.mkdir(current);
3521 + } catch (e) {
3522 + // ignore EEXIST
3523 + }
3524 + parent = current;
3525 + }
3526 + return current;
3527 + },createFile:function (parent, name, properties, canRead, canWrite) {
3528 + var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
3529 + var mode = FS.getMode(canRead, canWrite);
3530 + return FS.create(path, mode);
3531 + },createDataFile:function (parent, name, data, canRead, canWrite, canOwn) {
3532 + var path = name ? PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name) : parent;
3533 + var mode = FS.getMode(canRead, canWrite);
3534 + var node = FS.create(path, mode);
3535 + if (data) {
3536 + if (typeof data === 'string') {
3537 + var arr = new Array(data.length);
3538 + for (var i = 0, len = data.length; i < len; ++i) arr[i] = data.charCodeAt(i);
3539 + data = arr;
3540 + }
3541 + // make sure we can write to the file
3542 + FS.chmod(node, mode | 146);
3543 + var stream = FS.open(node, 'w');
3544 + FS.write(stream, data, 0, data.length, 0, canOwn);
3545 + FS.close(stream);
3546 + FS.chmod(node, mode);
3547 + }
3548 + return node;
3549 + },createDevice:function (parent, name, input, output) {
3550 + var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
3551 + var mode = FS.getMode(!!input, !!output);
3552 + if (!FS.createDevice.major) FS.createDevice.major = 64;
3553 + var dev = FS.makedev(FS.createDevice.major++, 0);
3554 + // Create a fake device that a set of stream ops to emulate
3555 + // the old behavior.
3556 + FS.registerDevice(dev, {
3557 + open: function(stream) {
3558 + stream.seekable = false;
3559 + },
3560 + close: function(stream) {
3561 + // flush any pending line data
3562 + if (output && output.buffer && output.buffer.length) {
3563 + output(10);
3564 + }
3565 + },
3566 + read: function(stream, buffer, offset, length, pos /* ignored */) {
3567 + var bytesRead = 0;
3568 + for (var i = 0; i < length; i++) {
3569 + var result;
3570 + try {
3571 + result = input();
3572 + } catch (e) {
3573 + throw new FS.ErrnoError(ERRNO_CODES.EIO);
3574 + }
3575 + if (result === undefined && bytesRead === 0) {
3576 + throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
3577 + }
3578 + if (result === null || result === undefined) break;
3579 + bytesRead++;
3580 + buffer[offset+i] = result;
3581 + }
3582 + if (bytesRead) {
3583 + stream.node.timestamp = Date.now();
3584 + }
3585 + return bytesRead;
3586 + },
3587 + write: function(stream, buffer, offset, length, pos) {
3588 + for (var i = 0; i < length; i++) {
3589 + try {
3590 + output(buffer[offset+i]);
3591 + } catch (e) {
3592 + throw new FS.ErrnoError(ERRNO_CODES.EIO);
3593 + }
3594 + }
3595 + if (length) {
3596 + stream.node.timestamp = Date.now();
3597 + }
3598 + return i;
3599 + }
3600 + });
3601 + return FS.mkdev(path, mode, dev);
3602 + },createLink:function (parent, name, target, canRead, canWrite) {
3603 + var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
3604 + return FS.symlink(target, path);
3605 + },forceLoadFile:function (obj) {
3606 + if (obj.isDevice || obj.isFolder || obj.link || obj.contents) return true;
3607 + var success = true;
3608 + if (typeof XMLHttpRequest !== 'undefined') {
3609 + throw new Error("Lazy loading should have been performed (contents set) in createLazyFile, but it was not. Lazy loading only works in web workers. Use --embed-file or --preload-file in emcc on the main thread.");
3610 + } else if (Module['read']) {
3611 + // Command-line.
3612 + try {
3613 + // WARNING: Can't read binary files in V8's d8 or tracemonkey's js, as
3614 + // read() will try to parse UTF8.
3615 + obj.contents = intArrayFromString(Module['read'](obj.url), true);
3616 + } catch (e) {
3617 + success = false;
3618 + }
3619 + } else {
3620 + throw new Error('Cannot load without read() or XMLHttpRequest.');
3621 + }
3622 + if (!success) ___setErrNo(ERRNO_CODES.EIO);
3623 + return success;
3624 + },createLazyFile:function (parent, name, url, canRead, canWrite) {
3625 + if (typeof XMLHttpRequest !== 'undefined') {
3626 + if (!ENVIRONMENT_IS_WORKER) throw 'Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc';
3627 + // Lazy chunked Uint8Array (implements get and length from Uint8Array). Actual getting is abstracted away for eventual reuse.
3628 + function LazyUint8Array() {
3629 + this.lengthKnown = false;
3630 + this.chunks = []; // Loaded chunks. Index is the chunk number
3631 + }
3632 + LazyUint8Array.prototype.get = function LazyUint8Array_get(idx) {
3633 + if (idx > this.length-1 || idx < 0) {
3634 + return undefined;
3635 + }
3636 + var chunkOffset = idx % this.chunkSize;
3637 + var chunkNum = Math.floor(idx / this.chunkSize);
3638 + return this.getter(chunkNum)[chunkOffset];
3639 + }
3640 + LazyUint8Array.prototype.setDataGetter = function LazyUint8Array_setDataGetter(getter) {
3641 + this.getter = getter;
3642 + }
3643 + LazyUint8Array.prototype.cacheLength = function LazyUint8Array_cacheLength() {
3644 + // Find length
3645 + var xhr = new XMLHttpRequest();
3646 + xhr.open('HEAD', url, false);
3647 + xhr.send(null);
3648 + if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error("Couldn't load " + url + ". Status: " + xhr.status);
3649 + var datalength = Number(xhr.getResponseHeader("Content-length"));
3650 + var header;
3651 + var hasByteServing = (header = xhr.getResponseHeader("Accept-Ranges")) && header === "bytes";
3652 + var chunkSize = 1024*1024; // Chunk size in bytes
3653 +
3654 + if (!hasByteServing) chunkSize = datalength;
3655 +
3656 + // Function to get a range from the remote URL.
3657 + var doXHR = (function(from, to) {
3658 + if (from > to) throw new Error("invalid range (" + from + ", " + to + ") or no bytes requested!");
3659 + if (to > datalength-1) throw new Error("only " + datalength + " bytes available! programmer error!");
3660 +
3661 + // TODO: Use mozResponseArrayBuffer, responseStream, etc. if available.
3662 + var xhr = new XMLHttpRequest();
3663 + xhr.open('GET', url, false);
3664 + if (datalength !== chunkSize) xhr.setRequestHeader("Range", "bytes=" + from + "-" + to);
3665 +
3666 + // Some hints to the browser that we want binary data.
3667 + if (typeof Uint8Array != 'undefined') xhr.responseType = 'arraybuffer';
3668 + if (xhr.overrideMimeType) {
3669 + xhr.overrideMimeType('text/plain; charset=x-user-defined');
3670 + }
3671 +
3672 + xhr.send(null);
3673 + if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error("Couldn't load " + url + ". Status: " + xhr.status);
3674 + if (xhr.response !== undefined) {
3675 + return new Uint8Array(xhr.response || []);
3676 + } else {
3677 + return intArrayFromString(xhr.responseText || '', true);
3678 + }
3679 + });
3680 + var lazyArray = this;
3681 + lazyArray.setDataGetter(function(chunkNum) {
3682 + var start = chunkNum * chunkSize;
3683 + var end = (chunkNum+1) * chunkSize - 1; // including this byte
3684 + end = Math.min(end, datalength-1); // if datalength-1 is selected, this is the last block
3685 + if (typeof(lazyArray.chunks[chunkNum]) === "undefined") {
3686 + lazyArray.chunks[chunkNum] = doXHR(start, end);
3687 + }
3688 + if (typeof(lazyArray.chunks[chunkNum]) === "undefined") throw new Error("doXHR failed!");
3689 + return lazyArray.chunks[chunkNum];
3690 + });
3691 +
3692 + this._length = datalength;
3693 + this._chunkSize = chunkSize;
3694 + this.lengthKnown = true;
3695 + }
3696 +
3697 + var lazyArray = new LazyUint8Array();
3698 + Object.defineProperty(lazyArray, "length", {
3699 + get: function() {
3700 + if(!this.lengthKnown) {
3701 + this.cacheLength();
3702 + }
3703 + return this._length;
3704 + }
3705 + });
3706 + Object.defineProperty(lazyArray, "chunkSize", {
3707 + get: function() {
3708 + if(!this.lengthKnown) {
3709 + this.cacheLength();
3710 + }
3711 + return this._chunkSize;
3712 + }
3713 + });
3714 +
3715 + var properties = { isDevice: false, contents: lazyArray };
3716 + } else {
3717 + var properties = { isDevice: false, url: url };
3718 + }
3719 +
3720 + var node = FS.createFile(parent, name, properties, canRead, canWrite);
3721 + // This is a total hack, but I want to get this lazy file code out of the
3722 + // core of MEMFS. If we want to keep this lazy file concept I feel it should
3723 + // be its own thin LAZYFS proxying calls to MEMFS.
3724 + if (properties.contents) {
3725 + node.contents = properties.contents;
3726 + } else if (properties.url) {
3727 + node.contents = null;
3728 + node.url = properties.url;
3729 + }
3730 + // override each stream op with one that tries to force load the lazy file first
3731 + var stream_ops = {};
3732 + var keys = Object.keys(node.stream_ops);
3733 + keys.forEach(function(key) {
3734 + var fn = node.stream_ops[key];
3735 + stream_ops[key] = function forceLoadLazyFile() {
3736 + if (!FS.forceLoadFile(node)) {
3737 + throw new FS.ErrnoError(ERRNO_CODES.EIO);
3738 + }
3739 + return fn.apply(null, arguments);
3740 + };
3741 + });
3742 + // use a custom read function
3743 + stream_ops.read = function stream_ops_read(stream, buffer, offset, length, position) {
3744 + if (!FS.forceLoadFile(node)) {
3745 + throw new FS.ErrnoError(ERRNO_CODES.EIO);
3746 + }
3747 + var contents = stream.node.contents;
3748 + if (position >= contents.length)
3749 + return 0;
3750 + var size = Math.min(contents.length - position, length);
3751 + assert(size >= 0);
3752 + if (contents.slice) { // normal array
3753 + for (var i = 0; i < size; i++) {
3754 + buffer[offset + i] = contents[position + i];
3755 + }
3756 + } else {
3757 + for (var i = 0; i < size; i++) { // LazyUint8Array from sync binary XHR
3758 + buffer[offset + i] = contents.get(position + i);
3759 + }
3760 + }
3761 + return size;
3762 + };
3763 + node.stream_ops = stream_ops;
3764 + return node;
3765 + },createPreloadedFile:function (parent, name, url, canRead, canWrite, onload, onerror, dontCreateFile, canOwn) {
3766 + Browser.init();
3767 + // TODO we should allow people to just pass in a complete filename instead
3768 + // of parent and name being that we just join them anyways
3769 + var fullname = name ? PATH.resolve(PATH.join2(parent, name)) : parent;
3770 + function processData(byteArray) {
3771 + function finish(byteArray) {
3772 + if (!dontCreateFile) {
3773 + FS.createDataFile(parent, name, byteArray, canRead, canWrite, canOwn);
3774 + }
3775 + if (onload) onload();
3776 + removeRunDependency('cp ' + fullname);
3777 + }
3778 + var handled = false;
3779 + Module['preloadPlugins'].forEach(function(plugin) {
3780 + if (handled) return;
3781 + if (plugin['canHandle'](fullname)) {
3782 + plugin['handle'](byteArray, fullname, finish, function() {
3783 + if (onerror) onerror();
3784 + removeRunDependency('cp ' + fullname);
3785 + });
3786 + handled = true;
3787 + }
3788 + });
3789 + if (!handled) finish(byteArray);
3790 + }
3791 + addRunDependency('cp ' + fullname);
3792 + if (typeof url == 'string') {
3793 + Browser.asyncLoad(url, function(byteArray) {
3794 + processData(byteArray);
3795 + }, onerror);
3796 + } else {
3797 + processData(url);
3798 + }
3799 + },indexedDB:function () {
3800 + return window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
3801 + },DB_NAME:function () {
3802 + return 'EM_FS_' + window.location.pathname;
3803 + },DB_VERSION:20,DB_STORE_NAME:"FILE_DATA",saveFilesToDB:function (paths, onload, onerror) {
3804 + onload = onload || function(){};
3805 + onerror = onerror || function(){};
3806 + var indexedDB = FS.indexedDB();
3807 + try {
3808 + var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION);
3809 + } catch (e) {
3810 + return onerror(e);
3811 + }
3812 + openRequest.onupgradeneeded = function openRequest_onupgradeneeded() {
3813 + console.log('creating db');
3814 + var db = openRequest.result;
3815 + db.createObjectStore(FS.DB_STORE_NAME);
3816 + };
3817 + openRequest.onsuccess = function openRequest_onsuccess() {
3818 + var db = openRequest.result;
3819 + var transaction = db.transaction([FS.DB_STORE_NAME], 'readwrite');
3820 + var files = transaction.objectStore(FS.DB_STORE_NAME);
3821 + var ok = 0, fail = 0, total = paths.length;
3822 + function finish() {
3823 + if (fail == 0) onload(); else onerror();
3824 + }
3825 + paths.forEach(function(path) {
3826 + var putRequest = files.put(FS.analyzePath(path).object.contents, path);
3827 + putRequest.onsuccess = function putRequest_onsuccess() { ok++; if (ok + fail == total) finish() };
3828 + putRequest.onerror = function putRequest_onerror() { fail++; if (ok + fail == total) finish() };
3829 + });
3830 + transaction.onerror = onerror;
3831 + };
3832 + openRequest.onerror = onerror;
3833 + },loadFilesFromDB:function (paths, onload, onerror) {
3834 + onload = onload || function(){};
3835 + onerror = onerror || function(){};
3836 + var indexedDB = FS.indexedDB();
3837 + try {
3838 + var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION);
3839 + } catch (e) {
3840 + return onerror(e);
3841 + }
3842 + openRequest.onupgradeneeded = onerror; // no database to load from
3843 + openRequest.onsuccess = function openRequest_onsuccess() {
3844 + var db = openRequest.result;
3845 + try {
3846 + var transaction = db.transaction([FS.DB_STORE_NAME], 'readonly');
3847 + } catch(e) {
3848 + onerror(e);
3849 + return;
3850 + }
3851 + var files = transaction.objectStore(FS.DB_STORE_NAME);
3852 + var ok = 0, fail = 0, total = paths.length;
3853 + function finish() {
3854 + if (fail == 0) onload(); else onerror();
3855 + }
3856 + paths.forEach(function(path) {
3857 + var getRequest = files.get(path);
3858 + getRequest.onsuccess = function getRequest_onsuccess() {
3859 + if (FS.analyzePath(path).exists) {
3860 + FS.unlink(path);
3861 + }
3862 + FS.createDataFile(PATH.dirname(path), PATH.basename(path), getRequest.result, true, true, true);
3863 + ok++;
3864 + if (ok + fail == total) finish();
3865 + };
3866 + getRequest.onerror = function getRequest_onerror() { fail++; if (ok + fail == total) finish() };
3867 + });
3868 + transaction.onerror = onerror;
3869 + };
3870 + openRequest.onerror = onerror;
3871 + }};var PATH={splitPath:function (filename) {
3872 + var splitPathRe = /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;
3873 + return splitPathRe.exec(filename).slice(1);
3874 + },normalizeArray:function (parts, allowAboveRoot) {
3875 + // if the path tries to go above the root, `up` ends up > 0
3876 + var up = 0;
3877 + for (var i = parts.length - 1; i >= 0; i--) {
3878 + var last = parts[i];
3879 + if (last === '.') {
3880 + parts.splice(i, 1);
3881 + } else if (last === '..') {
3882 + parts.splice(i, 1);
3883 + up++;
3884 + } else if (up) {
3885 + parts.splice(i, 1);
3886 + up--;
3887 + }
3888 + }
3889 + // if the path is allowed to go above the root, restore leading ..s
3890 + if (allowAboveRoot) {
3891 + for (; up--; up) {
3892 + parts.unshift('..');
3893 + }
3894 + }
3895 + return parts;
3896 + },normalize:function (path) {
3897 + var isAbsolute = path.charAt(0) === '/',
3898 + trailingSlash = path.substr(-1) === '/';
3899 + // Normalize the path
3900 + path = PATH.normalizeArray(path.split('/').filter(function(p) {
3901 + return !!p;
3902 + }), !isAbsolute).join('/');
3903 + if (!path && !isAbsolute) {
3904 + path = '.';
3905 + }
3906 + if (path && trailingSlash) {
3907 + path += '/';
3908 + }
3909 + return (isAbsolute ? '/' : '') + path;
3910 + },dirname:function (path) {
3911 + var result = PATH.splitPath(path),
3912 + root = result[0],
3913 + dir = result[1];
3914 + if (!root && !dir) {
3915 + // No dirname whatsoever
3916 + return '.';
3917 + }
3918 + if (dir) {
3919 + // It has a dirname, strip trailing slash
3920 + dir = dir.substr(0, dir.length - 1);
3921 + }
3922 + return root + dir;
3923 + },basename:function (path) {
3924 + // EMSCRIPTEN return '/'' for '/', not an empty string
3925 + if (path === '/') return '/';
3926 + var lastSlash = path.lastIndexOf('/');
3927 + if (lastSlash === -1) return path;
3928 + return path.substr(lastSlash+1);
3929 + },extname:function (path) {
3930 + return PATH.splitPath(path)[3];
3931 + },join:function () {
3932 + var paths = Array.prototype.slice.call(arguments, 0);
3933 + return PATH.normalize(paths.join('/'));
3934 + },join2:function (l, r) {
3935 + return PATH.normalize(l + '/' + r);
3936 + },resolve:function () {
3937 + var resolvedPath = '',
3938 + resolvedAbsolute = false;
3939 + for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) {
3940 + var path = (i >= 0) ? arguments[i] : FS.cwd();
3941 + // Skip empty and invalid entries
3942 + if (typeof path !== 'string') {
3943 + throw new TypeError('Arguments to path.resolve must be strings');
3944 + } else if (!path) {
3945 + continue;
3946 + }
3947 + resolvedPath = path + '/' + resolvedPath;
3948 + resolvedAbsolute = path.charAt(0) === '/';
3949 + }
3950 + // At this point the path should be resolved to a full absolute path, but
3951 + // handle relative paths to be safe (might happen when process.cwd() fails)
3952 + resolvedPath = PATH.normalizeArray(resolvedPath.split('/').filter(function(p) {
3953 + return !!p;
3954 + }), !resolvedAbsolute).join('/');
3955 + return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.';
3956 + },relative:function (from, to) {
3957 + from = PATH.resolve(from).substr(1);
3958 + to = PATH.resolve(to).substr(1);
3959 + function trim(arr) {
3960 + var start = 0;
3961 + for (; start < arr.length; start++) {
3962 + if (arr[start] !== '') break;
3963 + }
3964 + var end = arr.length - 1;
3965 + for (; end >= 0; end--) {
3966 + if (arr[end] !== '') break;
3967 + }
3968 + if (start > end) return [];
3969 + return arr.slice(start, end - start + 1);
3970 + }
3971 + var fromParts = trim(from.split('/'));
3972 + var toParts = trim(to.split('/'));
3973 + var length = Math.min(fromParts.length, toParts.length);
3974 + var samePartsLength = length;
3975 + for (var i = 0; i < length; i++) {
3976 + if (fromParts[i] !== toParts[i]) {
3977 + samePartsLength = i;
3978 + break;
3979 + }
3980 + }
3981 + var outputParts = [];
3982 + for (var i = samePartsLength; i < fromParts.length; i++) {
3983 + outputParts.push('..');
3984 + }
3985 + outputParts = outputParts.concat(toParts.slice(samePartsLength));
3986 + return outputParts.join('/');
3987 + }};var Browser={mainLoop:{scheduler:null,shouldPause:false,paused:false,queue:[],pause:function () {
3988 + Browser.mainLoop.shouldPause = true;
3989 + },resume:function () {
3990 + if (Browser.mainLoop.paused) {
3991 + Browser.mainLoop.paused = false;
3992 + Browser.mainLoop.scheduler();
3993 + }
3994 + Browser.mainLoop.shouldPause = false;
3995 + },updateStatus:function () {
3996 + if (Module['setStatus']) {
3997 + var message = Module['statusMessage'] || 'Please wait...';
3998 + var remaining = Browser.mainLoop.remainingBlockers;
3999 + var expected = Browser.mainLoop.expectedBlockers;
4000 + if (remaining) {
4001 + if (remaining < expected) {
4002 + Module['setStatus'](message + ' (' + (expected - remaining) + '/' + expected + ')');
4003 + } else {
4004 + Module['setStatus'](message);
4005 + }
4006 + } else {
4007 + Module['setStatus']('');
4008 + }
4009 + }
4010 + }},isFullScreen:false,pointerLock:false,moduleContextCreatedCallbacks:[],workers:[],init:function () {
4011 + if (!Module["preloadPlugins"]) Module["preloadPlugins"] = []; // needs to exist even in workers
4012 +
4013 + if (Browser.initted || ENVIRONMENT_IS_WORKER) return;
4014 + Browser.initted = true;
4015 +
4016 + try {
4017 + new Blob();
4018 + Browser.hasBlobConstructor = true;
4019 + } catch(e) {
4020 + Browser.hasBlobConstructor = false;
4021 + console.log("warning: no blob constructor, cannot create blobs with mimetypes");
4022 + }
4023 + Browser.BlobBuilder = typeof MozBlobBuilder != "undefined" ? MozBlobBuilder : (typeof WebKitBlobBuilder != "undefined" ? WebKitBlobBuilder : (!Browser.hasBlobConstructor ? console.log("warning: no BlobBuilder") : null));
4024 + Browser.URLObject = typeof window != "undefined" ? (window.URL ? window.URL : window.webkitURL) : undefined;
4025 + if (!Module.noImageDecoding && typeof Browser.URLObject === 'undefined') {
4026 + console.log("warning: Browser does not support creating object URLs. Built-in browser image decoding will not be available.");
4027 + Module.noImageDecoding = true;
4028 + }
4029 +
4030 + // Support for plugins that can process preloaded files. You can add more of these to
4031 + // your app by creating and appending to Module.preloadPlugins.
4032 + //
4033 + // Each plugin is asked if it can handle a file based on the file's name. If it can,
4034 + // it is given the file's raw data. When it is done, it calls a callback with the file's
4035 + // (possibly modified) data. For example, a plugin might decompress a file, or it
4036 + // might create some side data structure for use later (like an Image element, etc.).
4037 +
4038 + var imagePlugin = {};
4039 + imagePlugin['canHandle'] = function imagePlugin_canHandle(name) {
4040 + return !Module.noImageDecoding && /\.(jpg|jpeg|png|bmp)$/i.test(name);
4041 + };
4042 + imagePlugin['handle'] = function imagePlugin_handle(byteArray, name, onload, onerror) {
4043 + var b = null;
4044 + if (Browser.hasBlobConstructor) {
4045 + try {
4046 + b = new Blob([byteArray], { type: Browser.getMimetype(name) });
4047 + if (b.size !== byteArray.length) { // Safari bug #118630
4048 + // Safari's Blob can only take an ArrayBuffer
4049 + b = new Blob([(new Uint8Array(byteArray)).buffer], { type: Browser.getMimetype(name) });
4050 + }
4051 + } catch(e) {
4052 + Runtime.warnOnce('Blob constructor present but fails: ' + e + '; falling back to blob builder');
4053 + }
4054 + }
4055 + if (!b) {
4056 + var bb = new Browser.BlobBuilder();
4057 + bb.append((new Uint8Array(byteArray)).buffer); // we need to pass a buffer, and must copy the array to get the right data range
4058 + b = bb.getBlob();
4059 + }
4060 + var url = Browser.URLObject.createObjectURL(b);
4061 + assert(typeof url == 'string', 'createObjectURL must return a url as a string');
4062 + var img = new Image();
4063 + img.onload = function img_onload() {
4064 + assert(img.complete, 'Image ' + name + ' could not be decoded');
4065 + var canvas = document.createElement('canvas');
4066 + canvas.width = img.width;
4067 + canvas.height = img.height;
4068 + var ctx = canvas.getContext('2d');
4069 + ctx.drawImage(img, 0, 0);
4070 + Module["preloadedImages"][name] = canvas;
4071 + Browser.URLObject.revokeObjectURL(url);
4072 + if (onload) onload(byteArray);
4073 + };
4074 + img.onerror = function img_onerror(event) {
4075 + console.log('Image ' + url + ' could not be decoded');
4076 + if (onerror) onerror();
4077 + };
4078 + img.src = url;
4079 + };
4080 + Module['preloadPlugins'].push(imagePlugin);
4081 +
4082 + var audioPlugin = {};
4083 + audioPlugin['canHandle'] = function audioPlugin_canHandle(name) {
4084 + return !Module.noAudioDecoding && name.substr(-4) in { '.ogg': 1, '.wav': 1, '.mp3': 1 };
4085 + };
4086 + audioPlugin['handle'] = function audioPlugin_handle(byteArray, name, onload, onerror) {
4087 + var done = false;
4088 + function finish(audio) {
4089 + if (done) return;
4090 + done = true;
4091 + Module["preloadedAudios"][name] = audio;
4092 + if (onload) onload(byteArray);
4093 + }
4094 + function fail() {
4095 + if (done) return;
4096 + done = true;
4097 + Module["preloadedAudios"][name] = new Audio(); // empty shim
4098 + if (onerror) onerror();
4099 + }
4100 + if (Browser.hasBlobConstructor) {
4101 + try {
4102 + var b = new Blob([byteArray], { type: Browser.getMimetype(name) });
4103 + } catch(e) {
4104 + return fail();
4105 + }
4106 + var url = Browser.URLObject.createObjectURL(b); // XXX we never revoke this!
4107 + assert(typeof url == 'string', 'createObjectURL must return a url as a string');
4108 + var audio = new Audio();
4109 + audio.addEventListener('canplaythrough', function() { finish(audio) }, false); // use addEventListener due to chromium bug 124926
4110 + audio.onerror = function audio_onerror(event) {
4111 + if (done) return;
4112 + console.log('warning: browser could not fully decode audio ' + name + ', trying slower base64 approach');
4113 + function encode64(data) {
4114 + var BASE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
4115 + var PAD = '=';
4116 + var ret = '';
4117 + var leftchar = 0;
4118 + var leftbits = 0;
4119 + for (var i = 0; i < data.length; i++) {
4120 + leftchar = (leftchar << 8) | data[i];
4121 + leftbits += 8;
4122 + while (leftbits >= 6) {
4123 + var curr = (leftchar >> (leftbits-6)) & 0x3f;
4124 + leftbits -= 6;
4125 + ret += BASE[curr];
4126 + }
4127 + }
4128 + if (leftbits == 2) {
4129 + ret += BASE[(leftchar&3) << 4];
4130 + ret += PAD + PAD;
4131 + } else if (leftbits == 4) {
4132 + ret += BASE[(leftchar&0xf) << 2];
4133 + ret += PAD;
4134 + }
4135 + return ret;
4136 + }
4137 + audio.src = 'data:audio/x-' + name.substr(-3) + ';base64,' + encode64(byteArray);
4138 + finish(audio); // we don't wait for confirmation this worked - but it's worth trying
4139 + };
4140 + audio.src = url;
4141 + // workaround for chrome bug 124926 - we do not always get oncanplaythrough or onerror
4142 + Browser.safeSetTimeout(function() {
4143 + finish(audio); // try to use it even though it is not necessarily ready to play
4144 + }, 10000);
4145 + } else {
4146 + return fail();
4147 + }
4148 + };
4149 + Module['preloadPlugins'].push(audioPlugin);
4150 +
4151 + // Canvas event setup
4152 +
4153 + var canvas = Module['canvas'];
4154 + canvas.requestPointerLock = canvas['requestPointerLock'] ||
4155 + canvas['mozRequestPointerLock'] ||
4156 + canvas['webkitRequestPointerLock'];
4157 + canvas.exitPointerLock = document['exitPointerLock'] ||
4158 + document['mozExitPointerLock'] ||
4159 + document['webkitExitPointerLock'] ||
4160 + function(){}; // no-op if function does not exist
4161 + canvas.exitPointerLock = canvas.exitPointerLock.bind(document);
4162 +
4163 + function pointerLockChange() {
4164 + Browser.pointerLock = document['pointerLockElement'] === canvas ||
4165 + document['mozPointerLockElement'] === canvas ||
4166 + document['webkitPointerLockElement'] === canvas;
4167 + }
4168 +
4169 + document.addEventListener('pointerlockchange', pointerLockChange, false);
4170 + document.addEventListener('mozpointerlockchange', pointerLockChange, false);
4171 + document.addEventListener('webkitpointerlockchange', pointerLockChange, false);
4172 +
4173 + if (Module['elementPointerLock']) {
4174 + canvas.addEventListener("click", function(ev) {
4175 + if (!Browser.pointerLock && canvas.requestPointerLock) {
4176 + canvas.requestPointerLock();
4177 + ev.preventDefault();
4178 + }
4179 + }, false);
4180 + }
4181 + },createContext:function (canvas, useWebGL, setInModule, webGLContextAttributes) {
4182 + var ctx;
4183 + try {
4184 + if (useWebGL) {
4185 + var contextAttributes = {
4186 + antialias: false,
4187 + alpha: false
4188 + };
4189 +
4190 + if (webGLContextAttributes) {
4191 + for (var attribute in webGLContextAttributes) {
4192 + contextAttributes[attribute] = webGLContextAttributes[attribute];
4193 + }
4194 + }
4195 +
4196 +
4197 + var errorInfo = '?';
4198 + function onContextCreationError(event) {
4199 + errorInfo = event.statusMessage || errorInfo;
4200 + }
4201 + canvas.addEventListener('webglcontextcreationerror', onContextCreationError, false);
4202 + try {
4203 + ['experimental-webgl', 'webgl'].some(function(webglId) {
4204 + return ctx = canvas.getContext(webglId, contextAttributes);
4205 + });
4206 + } finally {
4207 + canvas.removeEventListener('webglcontextcreationerror', onContextCreationError, false);
4208 + }
4209 + } else {
4210 + ctx = canvas.getContext('2d');
4211 + }
4212 + if (!ctx) throw ':(';
4213 + } catch (e) {
4214 + Module.print('Could not create canvas: ' + [errorInfo, e]);
4215 + return null;
4216 + }
4217 + if (useWebGL) {
4218 + // Set the background of the WebGL canvas to black
4219 + canvas.style.backgroundColor = "black";
4220 +
4221 + // Warn on context loss
4222 + canvas.addEventListener('webglcontextlost', function(event) {
4223 + alert('WebGL context lost. You will need to reload the page.');
4224 + }, false);
4225 + }
4226 + if (setInModule) {
4227 + GLctx = Module.ctx = ctx;
4228 + Module.useWebGL = useWebGL;
4229 + Browser.moduleContextCreatedCallbacks.forEach(function(callback) { callback() });
4230 + Browser.init();
4231 + }
4232 + return ctx;
4233 + },destroyContext:function (canvas, useWebGL, setInModule) {},fullScreenHandlersInstalled:false,lockPointer:undefined,resizeCanvas:undefined,requestFullScreen:function (lockPointer, resizeCanvas) {
4234 + Browser.lockPointer = lockPointer;
4235 + Browser.resizeCanvas = resizeCanvas;
4236 + if (typeof Browser.lockPointer === 'undefined') Browser.lockPointer = true;
4237 + if (typeof Browser.resizeCanvas === 'undefined') Browser.resizeCanvas = false;
4238 +
4239 + var canvas = Module['canvas'];
4240 + function fullScreenChange() {
4241 + Browser.isFullScreen = false;
4242 + if ((document['webkitFullScreenElement'] || document['webkitFullscreenElement'] ||
4243 + document['mozFullScreenElement'] || document['mozFullscreenElement'] ||
4244 + document['fullScreenElement'] || document['fullscreenElement']) === canvas) {
4245 + canvas.cancelFullScreen = document['cancelFullScreen'] ||
4246 + document['mozCancelFullScreen'] ||
4247 + document['webkitCancelFullScreen'];
4248 + canvas.cancelFullScreen = canvas.cancelFullScreen.bind(document);
4249 + if (Browser.lockPointer) canvas.requestPointerLock();
4250 + Browser.isFullScreen = true;
4251 + if (Browser.resizeCanvas) Browser.setFullScreenCanvasSize();
4252 + } else if (Browser.resizeCanvas){
4253 + Browser.setWindowedCanvasSize();
4254 + }
4255 + if (Module['onFullScreen']) Module['onFullScreen'](Browser.isFullScreen);
4256 + }
4257 +
4258 + if (!Browser.fullScreenHandlersInstalled) {
4259 + Browser.fullScreenHandlersInstalled = true;
4260 + document.addEventListener('fullscreenchange', fullScreenChange, false);
4261 + document.addEventListener('mozfullscreenchange', fullScreenChange, false);
4262 + document.addEventListener('webkitfullscreenchange', fullScreenChange, false);
4263 + }
4264 +
4265 + canvas.requestFullScreen = canvas['requestFullScreen'] ||
4266 + canvas['mozRequestFullScreen'] ||
4267 + (canvas['webkitRequestFullScreen'] ? function() { canvas['webkitRequestFullScreen'](Element['ALLOW_KEYBOARD_INPUT']) } : null);
4268 + canvas.requestFullScreen();
4269 + },requestAnimationFrame:function requestAnimationFrame(func) {
4270 + if (typeof window === 'undefined') { // Provide fallback to setTimeout if window is undefined (e.g. in Node.js)
4271 + setTimeout(func, 1000/60);
4272 + } else {
4273 + if (!window.requestAnimationFrame) {
4274 + window.requestAnimationFrame = window['requestAnimationFrame'] ||
4275 + window['mozRequestAnimationFrame'] ||
4276 + window['webkitRequestAnimationFrame'] ||
4277 + window['msRequestAnimationFrame'] ||
4278 + window['oRequestAnimationFrame'] ||
4279 + window['setTimeout'];
4280 + }
4281 + window.requestAnimationFrame(func);
4282 + }
4283 + },safeCallback:function (func) {
4284 + return function() {
4285 + if (!ABORT) return func.apply(null, arguments);
4286 + };
4287 + },safeRequestAnimationFrame:function (func) {
4288 + return Browser.requestAnimationFrame(function() {
4289 + if (!ABORT) func();
4290 + });
4291 + },safeSetTimeout:function (func, timeout) {
4292 + return setTimeout(function() {
4293 + if (!ABORT) func();
4294 + }, timeout);
4295 + },safeSetInterval:function (func, timeout) {
4296 + return setInterval(function() {
4297 + if (!ABORT) func();
4298 + }, timeout);
4299 + },getMimetype:function (name) {
4300 + return {
4301 + 'jpg': 'image/jpeg',
4302 + 'jpeg': 'image/jpeg',
4303 + 'png': 'image/png',
4304 + 'bmp': 'image/bmp',
4305 + 'ogg': 'audio/ogg',
4306 + 'wav': 'audio/wav',
4307 + 'mp3': 'audio/mpeg'
4308 + }[name.substr(name.lastIndexOf('.')+1)];
4309 + },getUserMedia:function (func) {
4310 + if(!window.getUserMedia) {
4311 + window.getUserMedia = navigator['getUserMedia'] ||
4312 + navigator['mozGetUserMedia'];
4313 + }
4314 + window.getUserMedia(func);
4315 + },getMovementX:function (event) {
4316 + return event['movementX'] ||
4317 + event['mozMovementX'] ||
4318 + event['webkitMovementX'] ||
4319 + 0;
4320 + },getMovementY:function (event) {
4321 + return event['movementY'] ||
4322 + event['mozMovementY'] ||
4323 + event['webkitMovementY'] ||
4324 + 0;
4325 + },mouseX:0,mouseY:0,mouseMovementX:0,mouseMovementY:0,calculateMouseEvent:function (event) { // event should be mousemove, mousedown or mouseup
4326 + if (Browser.pointerLock) {
4327 + // When the pointer is locked, calculate the coordinates
4328 + // based on the movement of the mouse.
4329 + // Workaround for Firefox bug 764498
4330 + if (event.type != 'mousemove' &&
4331 + ('mozMovementX' in event)) {
4332 + Browser.mouseMovementX = Browser.mouseMovementY = 0;
4333 + } else {
4334 + Browser.mouseMovementX = Browser.getMovementX(event);
4335 + Browser.mouseMovementY = Browser.getMovementY(event);
4336 + }
4337 +
4338 + // check if SDL is available
4339 + if (typeof SDL != "undefined") {
4340 + Browser.mouseX = SDL.mouseX + Browser.mouseMovementX;
4341 + Browser.mouseY = SDL.mouseY + Browser.mouseMovementY;
4342 + } else {
4343 + // just add the mouse delta to the current absolut mouse position
4344 + // FIXME: ideally this should be clamped against the canvas size and zero
4345 + Browser.mouseX += Browser.mouseMovementX;
4346 + Browser.mouseY += Browser.mouseMovementY;
4347 + }
4348 + } else {
4349 + // Otherwise, calculate the movement based on the changes
4350 + // in the coordinates.
4351 + var rect = Module["canvas"].getBoundingClientRect();
4352 + var x, y;
4353 +
4354 + // Neither .scrollX or .pageXOffset are defined in a spec, but
4355 + // we prefer .scrollX because it is currently in a spec draft.
4356 + // (see: http://www.w3.org/TR/2013/WD-cssom-view-20131217/)
4357 + var scrollX = ((typeof window.scrollX !== 'undefined') ? window.scrollX : window.pageXOffset);
4358 + var scrollY = ((typeof window.scrollY !== 'undefined') ? window.scrollY : window.pageYOffset);
4359 + // If this assert lands, it's likely because the browser doesn't support scrollX or pageXOffset
4360 + // and we have no viable fallback.
4361 + assert((typeof scrollX !== 'undefined') && (typeof scrollY !== 'undefined'), 'Unable to retrieve scroll position, mouse positions likely broken.');
4362 + if (event.type == 'touchstart' ||
4363 + event.type == 'touchend' ||
4364 + event.type == 'touchmove') {
4365 + var t = event.touches.item(0);
4366 + if (t) {
4367 + x = t.pageX - (scrollX + rect.left);
4368 + y = t.pageY - (scrollY + rect.top);
4369 + } else {
4370 + return;
4371 + }
4372 + } else {
4373 + x = event.pageX - (scrollX + rect.left);
4374 + y = event.pageY - (scrollY + rect.top);
4375 + }
4376 +
4377 + // the canvas might be CSS-scaled compared to its backbuffer;
4378 + // SDL-using content will want mouse coordinates in terms
4379 + // of backbuffer units.
4380 + var cw = Module["canvas"].width;
4381 + var ch = Module["canvas"].height;
4382 + x = x * (cw / rect.width);
4383 + y = y * (ch / rect.height);
4384 +
4385 + Browser.mouseMovementX = x - Browser.mouseX;
4386 + Browser.mouseMovementY = y - Browser.mouseY;
4387 + Browser.mouseX = x;
4388 + Browser.mouseY = y;
4389 + }
4390 + },xhrLoad:function (url, onload, onerror) {
4391 + var xhr = new XMLHttpRequest();
4392 + xhr.open('GET', url, true);
4393 + xhr.responseType = 'arraybuffer';
4394 + xhr.onload = function xhr_onload() {
4395 + if (xhr.status == 200 || (xhr.status == 0 && xhr.response)) { // file URLs can return 0
4396 + onload(xhr.response);
4397 + } else {
4398 + onerror();
4399 + }
4400 + };
4401 + xhr.onerror = onerror;
4402 + xhr.send(null);
4403 + },asyncLoad:function (url, onload, onerror, noRunDep) {
4404 + Browser.xhrLoad(url, function(arrayBuffer) {
4405 + assert(arrayBuffer, 'Loading data file "' + url + '" failed (no arrayBuffer).');
4406 + onload(new Uint8Array(arrayBuffer));
4407 + if (!noRunDep) removeRunDependency('al ' + url);
4408 + }, function(event) {
4409 + if (onerror) {
4410 + onerror();
4411 + } else {
4412 + throw 'Loading data file "' + url + '" failed.';
4413 + }
4414 + });
4415 + if (!noRunDep) addRunDependency('al ' + url);
4416 + },resizeListeners:[],updateResizeListeners:function () {
4417 + var canvas = Module['canvas'];
4418 + Browser.resizeListeners.forEach(function(listener) {
4419 + listener(canvas.width, canvas.height);
4420 + });
4421 + },setCanvasSize:function (width, height, noUpdates) {
4422 + var canvas = Module['canvas'];
4423 + canvas.width = width;
4424 + canvas.height = height;
4425 + if (!noUpdates) Browser.updateResizeListeners();
4426 + },windowedWidth:0,windowedHeight:0,setFullScreenCanvasSize:function () {
4427 + var canvas = Module['canvas'];
4428 + this.windowedWidth = canvas.width;
4429 + this.windowedHeight = canvas.height;
4430 + canvas.width = screen.width;
4431 + canvas.height = screen.height;
4432 + // check if SDL is available
4433 + if (typeof SDL != "undefined") {
4434 + var flags = HEAPU32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)];
4435 + flags = flags | 0x00800000; // set SDL_FULLSCREEN flag
4436 + HEAP32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)]=flags
4437 + }
4438 + Browser.updateResizeListeners();
4439 + },setWindowedCanvasSize:function () {
4440 + var canvas = Module['canvas'];
4441 + canvas.width = this.windowedWidth;
4442 + canvas.height = this.windowedHeight;
4443 + // check if SDL is available
4444 + if (typeof SDL != "undefined") {
4445 + var flags = HEAPU32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)];
4446 + flags = flags & ~0x00800000; // clear SDL_FULLSCREEN flag
4447 + HEAP32[((SDL.screen+Runtime.QUANTUM_SIZE*0)>>2)]=flags
4448 + }
4449 + Browser.updateResizeListeners();
4450 + }};
4451 +___errno_state = Runtime.staticAlloc(4); HEAP32[((___errno_state)>>2)]=0;
4452 +Module["requestFullScreen"] = function Module_requestFullScreen(lockPointer, resizeCanvas) { Browser.requestFullScreen(lockPointer, resizeCanvas) };
4453 + Module["requestAnimationFrame"] = function Module_requestAnimationFrame(func) { Browser.requestAnimationFrame(func) };
4454 + Module["setCanvasSize"] = function Module_setCanvasSize(width, height, noUpdates) { Browser.setCanvasSize(width, height, noUpdates) };
4455 + Module["pauseMainLoop"] = function Module_pauseMainLoop() { Browser.mainLoop.pause() };
4456 + Module["resumeMainLoop"] = function Module_resumeMainLoop() { Browser.mainLoop.resume() };
4457 + Module["getUserMedia"] = function Module_getUserMedia() { Browser.getUserMedia() }
4458 +FS.staticInit();__ATINIT__.unshift({ func: function() { if (!Module["noFSInit"] && !FS.init.initialized) FS.init() } });__ATMAIN__.push({ func: function() { FS.ignorePermissions = false } });__ATEXIT__.push({ func: function() { FS.quit() } });Module["FS_createFolder"] = FS.createFolder;Module["FS_createPath"] = FS.createPath;Module["FS_createDataFile"] = FS.createDataFile;Module["FS_createPreloadedFile"] = FS.createPreloadedFile;Module["FS_createLazyFile"] = FS.createLazyFile;Module["FS_createLink"] = FS.createLink;Module["FS_createDevice"] = FS.createDevice;
4459 +__ATINIT__.unshift({ func: function() { TTY.init() } });__ATEXIT__.push({ func: function() { TTY.shutdown() } });TTY.utf8 = new Runtime.UTF8Processor();
4460 +if (ENVIRONMENT_IS_NODE) { var fs = require("fs"); NODEFS.staticInit(); }
4461 +STACK_BASE = STACKTOP = Runtime.alignMemory(STATICTOP);
4462 +
4463 +staticSealed = true; // seal the static portion of memory
4464 +
4465 +STACK_MAX = STACK_BASE + 5242880;
4466 +
4467 +DYNAMIC_BASE = DYNAMICTOP = Runtime.alignMemory(STACK_MAX);
4468 +
4469 +assert(DYNAMIC_BASE < TOTAL_MEMORY, "TOTAL_MEMORY not big enough for stack");
4470 +
4471 +
4472 +
4473 +var FUNCTION_TABLE = [0, 0];
4474 +
4475 +// EMSCRIPTEN_START_FUNCS
4476 +
4477 +function _bitmap_decompress_15($output,$output_width,$output_height,$input_width,$input_height,$input,$size){
4478 + var label=0;
4479 + var sp=STACKTOP; (assert((STACKTOP|0) < (STACK_MAX|0))|0);
4480 + label = 1;
4481 + while(1)switch(label){
4482 + case 1:
4483 + var $1;
4484 + var $2;
4485 + var $3;
4486 + var $4;
4487 + var $5;
4488 + var $6;
4489 + var $7;
4490 + var $temp;
4491 + var $rv;
4492 + var $y;
4493 + var $x;
4494 + var $a;
4495 + var $r;
4496 + var $g;
4497 + var $b;
4498 + $1=$output;
4499 + $2=$output_width;
4500 + $3=$output_height;
4501 + $4=$input_width;
4502 + $5=$input_height;
4503 + $6=$input;
4504 + $7=$size;
4505 + var $8=$4;
4506 + var $9=$5;
4507 + var $10=(Math_imul($8,$9)|0);
4508 + var $11=($10<<1);
4509 + var $12=_malloc($11);
4510 + $temp=$12;
4511 + var $13=$temp;
4512 + var $14=$4;
4513 + var $15=$5;
4514 + var $16=$6;
4515 + var $17=$7;
4516 + var $18=_bitmap_decompress2($13,$14,$15,$16,$17);
4517 + $rv=$18;
4518 + $y=0;
4519 + label=2;break;
4520 + case 2:
4521 + var $20=$y;
4522 + var $21=$3;
4523 + var $22=($20|0)<($21|0);
4524 + if($22){label=3;break;}else{label=9;break;}
4525 + case 3:
4526 + $x=0;
4527 + label=4;break;
4528 + case 4:
4529 + var $25=$x;
4530 + var $26=$2;
4531 + var $27=($25|0)<($26|0);
4532 + if($27){label=5;break;}else{label=7;break;}
4533 + case 5:
4534 + var $29=$y;
4535 + var $30=$4;
4536 + var $31=(Math_imul($29,$30)|0);
4537 + var $32=$x;
4538 + var $33=((($31)+($32))|0);
4539 + var $34=$temp;
4540 + var $35=$34;
4541 + var $36=(($35+($33<<1))|0);
4542 + var $37=HEAP16[(($36)>>1)];
4543 + $a=$37;
4544 + var $38=$a;
4545 + var $39=($38&65535);
4546 + var $40=$39&31744;
4547 + var $41=$40>>10;
4548 + var $42=(($41)&255);
4549 + $r=$42;
4550 + var $43=$a;
4551 + var $44=($43&65535);
4552 + var $45=$44&992;
4553 + var $46=$45>>5;
4554 + var $47=(($46)&255);
4555 + $g=$47;
4556 + var $48=$a;
4557 + var $49=($48&65535);
4558 + var $50=$49&31;
4559 + var $51=(($50)&255);
4560 + $b=$51;
4561 + var $52=$r;
4562 + var $53=($52&255);
4563 + var $54=((($53)*(255))&-1);
4564 + var $55=(((($54|0))/(31))&-1);
4565 + var $56=(($55)&255);
4566 + $r=$56;
4567 + var $57=$g;
4568 + var $58=($57&255);
4569 + var $59=((($58)*(255))&-1);
4570 + var $60=(((($59|0))/(31))&-1);
4571 + var $61=(($60)&255);
4572 + $g=$61;
4573 + var $62=$b;
4574 + var $63=($62&255);
4575 + var $64=((($63)*(255))&-1);
4576 + var $65=(((($64|0))/(31))&-1);
4577 + var $66=(($65)&255);
4578 + $b=$66;
4579 + var $67=$b;
4580 + var $68=($67&255);
4581 + var $69=$68<<16;
4582 + var $70=-16777216|$69;
4583 + var $71=$g;
4584 + var $72=($71&255);
4585 + var $73=$72<<8;
4586 + var $74=$70|$73;
4587 + var $75=$r;
4588 + var $76=($75&255);
4589 + var $77=$74|$76;
4590 + var $78=$y;
4591 + var $79=$2;
4592 + var $80=(Math_imul($78,$79)|0);
4593 + var $81=$x;
4594 + var $82=((($80)+($81))|0);
4595 + var $83=$1;
4596 + var $84=$83;
4597 + var $85=(($84+($82<<2))|0);
4598 + HEAP32[(($85)>>2)]=$77;
4599 + label=6;break;
4600 + case 6:
4601 + var $87=$x;
4602 + var $88=((($87)+(1))|0);
4603 + $x=$88;
4604 + label=4;break;
4605 + case 7:
4606 + label=8;break;
4607 + case 8:
4608 + var $91=$y;
4609 + var $92=((($91)+(1))|0);
4610 + $y=$92;
4611 + label=2;break;
4612 + case 9:
4613 + var $94=$temp;
4614 + _free($94);
4615 + var $95=$rv;
4616 + STACKTOP=sp;return $95;
4617 + default: assert(0, "bad label: " + label);
4618 + }
4619 +
4620 +}
4621 +Module["_bitmap_decompress_15"] = _bitmap_decompress_15;
4622 +
4623 +function _bitmap_decompress2($output,$width,$height,$input,$size){
4624 + var label=0;
4625 + var sp=STACKTOP; (assert((STACKTOP|0) < (STACK_MAX|0))|0);
4626 + label = 1;
4627 + while(1)switch(label){
4628 + case 1:
4629 + var $1;
4630 + var $2;
4631 + var $3;
4632 + var $4;
4633 + var $5;
4634 + var $6;
4635 + var $end;
4636 + var $prevline;
4637 + var $line;
4638 + var $opcode;
4639 + var $count;
4640 + var $offset;
4641 + var $isfillormix;
4642 + var $x;
4643 + var $lastopcode;
4644 + var $insertmix;
4645 + var $bicolour;
4646 + var $code;
4647 + var $colour1;
4648 + var $colour2;
4649 + var $mixmask;
4650 + var $mask;
4651 + var $mix;
4652 + var $fom_mask;
4653 + $2=$output;
4654 + $3=$width;
4655 + $4=$height;
4656 + $5=$input;
4657 + $6=$size;
4658 + var $7=$5;
4659 + var $8=$6;
4660 + var $9=(($7+$8)|0);
4661 + $end=$9;
4662 + $prevline=0;
4663 + $line=0;
4664 + var $10=$3;
4665 + $x=$10;
4666 + $lastopcode=-1;
4667 + $insertmix=0;
4668 + $bicolour=0;
4669 + $colour1=0;
4670 + $colour2=0;
4671 + $mask=0;
4672 + $mix=-1;
4673 + $fom_mask=0;
4674 + label=2;break;
4675 + case 2:
4676 + var $12=$5;
4677 + var $13=$end;
4678 + var $14=($12>>>0)<($13>>>0);
4679 + if($14){label=3;break;}else{label=346;break;}
4680 + case 3:
4681 + $fom_mask=0;
4682 + var $16=$5;
4683 + var $17=(($16+1)|0);
4684 + $5=$17;
4685 + var $18=HEAP8[($16)];
4686 + $code=$18;
4687 + var $19=$code;
4688 + var $20=($19&255);
4689 + var $21=$20>>4;
4690 + $opcode=$21;
4691 + var $22=$opcode;
4692 + if(($22|0)==12|($22|0)==13|($22|0)==14){ label=4;break;}else if(($22|0)==15){ label=5;break;}else{label=9;break;}
4693 + case 4:
4694 + var $24=$opcode;
4695 + var $25=((($24)-(6))|0);
4696 + $opcode=$25;
4697 + var $26=$code;
4698 + var $27=($26&255);
4699 + var $28=$27&15;
4700 + $count=$28;
4701 + $offset=16;
4702 + label=10;break;
4703 + case 5:
4704 + var $30=$code;
4705 + var $31=($30&255);
4706 + var $32=$31&15;
4707 + $opcode=$32;
4708 + var $33=$opcode;
4709 + var $34=($33|0)<9;
4710 + if($34){label=6;break;}else{label=7;break;}
4711 + case 6:
4712 + var $36=$5;
4713 + var $37=(($36+1)|0);
4714 + $5=$37;
4715 + var $38=HEAP8[($36)];
4716 + var $39=($38&255);
4717 + $count=$39;
4718 + var $40=$5;
4719 + var $41=(($40+1)|0);
4720 + $5=$41;
4721 + var $42=HEAP8[($40)];
4722 + var $43=($42&255);
4723 + var $44=$43<<8;
4724 + var $45=$count;
4725 + var $46=$45|$44;
4726 + $count=$46;
4727 + label=8;break;
4728 + case 7:
4729 + var $48=$opcode;
4730 + var $49=($48|0)<11;
4731 + var $50=($49?8:1);
4732 + $count=$50;
4733 + label=8;break;
4734 + case 8:
4735 + $offset=0;
4736 + label=10;break;
4737 + case 9:
4738 + var $53=$opcode;
4739 + var $54=$53>>1;
4740 + $opcode=$54;
4741 + var $55=$code;
4742 + var $56=($55&255);
4743 + var $57=$56&31;
4744 + $count=$57;
4745 + $offset=32;
4746 + label=10;break;
4747 + case 10:
4748 + var $59=$offset;
4749 + var $60=($59|0)!=0;
4750 + if($60){label=11;break;}else{label=22;break;}
4751 + case 11:
4752 + var $62=$opcode;
4753 + var $63=($62|0)==2;
4754 + if($63){var $68=1;label=13;break;}else{label=12;break;}
4755 + case 12:
4756 + var $65=$opcode;
4757 + var $66=($65|0)==7;
4758 + var $68=$66;label=13;break;
4759 + case 13:
4760 + var $68;
4761 + var $69=($68&1);
4762 + $isfillormix=$69;
4763 + var $70=$count;
4764 + var $71=($70|0)==0;
4765 + if($71){label=14;break;}else{label=18;break;}
4766 + case 14:
4767 + var $73=$isfillormix;
4768 + var $74=($73|0)!=0;
4769 + if($74){label=15;break;}else{label=16;break;}
4770 + case 15:
4771 + var $76=$5;
4772 + var $77=(($76+1)|0);
4773 + $5=$77;
4774 + var $78=HEAP8[($76)];
4775 + var $79=($78&255);
4776 + var $80=((($79)+(1))|0);
4777 + $count=$80;
4778 + label=17;break;
4779 + case 16:
4780 + var $82=$5;
4781 + var $83=(($82+1)|0);
4782 + $5=$83;
4783 + var $84=HEAP8[($82)];
4784 + var $85=($84&255);
4785 + var $86=$offset;
4786 + var $87=((($85)+($86))|0);
4787 + $count=$87;
4788 + label=17;break;
4789 + case 17:
4790 + label=21;break;
4791 + case 18:
4792 + var $90=$isfillormix;
4793 + var $91=($90|0)!=0;
4794 + if($91){label=19;break;}else{label=20;break;}
4795 + case 19:
4796 + var $93=$count;
4797 + var $94=$93<<3;
4798 + $count=$94;
4799 + label=20;break;
4800 + case 20:
4801 + label=21;break;
4802 + case 21:
4803 + label=22;break;
4804 + case 22:
4805 + var $98=$opcode;
4806 + switch(($98|0)){case 0:{ label=23;break;}case 8:{ label=28;break;}case 3:{ label=29;break;}case 6:case 7:{ label=30;break;}case 9:{ label=31;break;}case 10:{ label=32;break;}default:{label=33;break;}}break;
4807 + case 23:
4808 + var $100=$lastopcode;
4809 + var $101=$opcode;
4810 + var $102=($100|0)==($101|0);
4811 + if($102){label=24;break;}else{label=27;break;}
4812 + case 24:
4813 + var $104=$x;
4814 + var $105=$3;
4815 + var $106=($104|0)==($105|0);
4816 + if($106){label=25;break;}else{label=26;break;}
4817 + case 25:
4818 + var $108=$prevline;
4819 + var $109=($108|0)==0;
4820 + if($109){label=27;break;}else{label=26;break;}
4821 + case 26:
4822 + $insertmix=1;
4823 + label=27;break;
4824 + case 27:
4825 + label=33;break;
4826 + case 28:
4827 + var $113=$5;
4828 + var $114=(($113+1)|0);
4829 + $5=$114;
4830 + var $115=HEAP8[($113)];
4831 + var $116=($115&255);
4832 + $colour1=$116;
4833 + var $117=$5;
4834 + var $118=(($117+1)|0);
4835 + $5=$118;
4836 + var $119=HEAP8[($117)];
4837 + var $120=($119&255);
4838 + var $121=$120<<8;
4839 + var $122=$colour1;
4840 + var $123=($122&65535);
4841 + var $124=$123|$121;
4842 + var $125=(($124)&65535);
4843 + $colour1=$125;
4844 + label=29;break;
4845 + case 29:
4846 + var $127=$5;
4847 + var $128=(($127+1)|0);
4848 + $5=$128;
4849 + var $129=HEAP8[($127)];
4850 + var $130=($129&255);
4851 + $colour2=$130;
4852 + var $131=$5;
4853 + var $132=(($131+1)|0);
4854 + $5=$132;
4855 + var $133=HEAP8[($131)];
4856 + var $134=($133&255);
4857 + var $135=$134<<8;
4858 + var $136=$colour2;
4859 + var $137=($136&65535);
4860 + var $138=$137|$135;
4861 + var $139=(($138)&65535);
4862 + $colour2=$139;
4863 + label=33;break;
4864 + case 30:
4865 + var $141=$5;
4866 + var $142=(($141+1)|0);
4867 + $5=$142;
4868 + var $143=HEAP8[($141)];
4869 + var $144=($143&255);
4870 + $mix=$144;
4871 + var $145=$5;
4872 + var $146=(($145+1)|0);
4873 + $5=$146;
4874 + var $147=HEAP8[($145)];
4875 + var $148=($147&255);
4876 + var $149=$148<<8;
4877 + var $150=$mix;
4878 + var $151=($150&65535);
4879 + var $152=$151|$149;
4880 + var $153=(($152)&65535);
4881 + $mix=$153;
4882 + var $154=$opcode;
4883 + var $155=((($154)-(5))|0);
4884 + $opcode=$155;
4885 + label=33;break;
4886 + case 31:
4887 + $mask=3;
4888 + $opcode=2;
4889 + $fom_mask=3;
4890 + label=33;break;
4891 + case 32:
4892 + $mask=5;
4893 + $opcode=2;
4894 + $fom_mask=5;
4895 + label=33;break;
4896 + case 33:
4897 + var $159=$opcode;
4898 + $lastopcode=$159;
4899 + $mixmask=0;
4900 + label=34;break;
4901 + case 34:
4902 + var $161=$count;
4903 + var $162=($161|0)>0;
4904 + if($162){label=35;break;}else{label=345;break;}
4905 + case 35:
4906 + var $164=$x;
4907 + var $165=$3;
4908 + var $166=($164|0)>=($165|0);
4909 + if($166){label=36;break;}else{label=39;break;}
4910 + case 36:
4911 + var $168=$4;
4912 + var $169=($168|0)<=0;
4913 + if($169){label=37;break;}else{label=38;break;}
4914 + case 37:
4915 + $1=0;
4916 + label=347;break;
4917 + case 38:
4918 + $x=0;
4919 + var $172=$4;
4920 + var $173=((($172)-(1))|0);
4921 + $4=$173;
4922 + var $174=$line;
4923 + $prevline=$174;
4924 + var $175=$2;
4925 + var $176=$175;
4926 + var $177=$4;
4927 + var $178=$3;
4928 + var $179=(Math_imul($177,$178)|0);
4929 + var $180=(($176+($179<<1))|0);
4930 + $line=$180;
4931 + label=39;break;
4932 + case 39:
4933 + var $182=$opcode;
4934 + switch(($182|0)){case 3:{ label=261;break;}case 4:{ label=272;break;}case 8:{ label=283;break;}case 13:{ label=321;break;}case 14:{ label=332;break;}case 0:{ label=40;break;}case 1:{ label=69;break;}case 2:{ label=93;break;}default:{label=343;break;}}break;
4935 + case 40:
4936 + var $184=$insertmix;
4937 + var $185=($184|0)!=0;
4938 + if($185){label=41;break;}else{label=45;break;}
4939 + case 41:
4940 + var $187=$prevline;
4941 + var $188=($187|0)==0;
4942 + if($188){label=42;break;}else{label=43;break;}
4943 + case 42:
4944 + var $190=$mix;
4945 + var $191=$x;
4946 + var $192=$line;
4947 + var $193=(($192+($191<<1))|0);
4948 + HEAP16[(($193)>>1)]=$190;
4949 + label=44;break;
4950 + case 43:
4951 + var $195=$x;
4952 + var $196=$prevline;
4953 + var $197=(($196+($195<<1))|0);
4954 + var $198=HEAP16[(($197)>>1)];
4955 + var $199=($198&65535);
4956 + var $200=$mix;
4957 + var $201=($200&65535);
4958 + var $202=$199^$201;
4959 + var $203=(($202)&65535);
4960 + var $204=$x;
4961 + var $205=$line;
4962 + var $206=(($205+($204<<1))|0);
4963 + HEAP16[(($206)>>1)]=$203;
4964 + label=44;break;
4965 + case 44:
4966 + $insertmix=0;
4967 + var $208=$count;
4968 + var $209=((($208)-(1))|0);
4969 + $count=$209;
4970 + var $210=$x;
4971 + var $211=((($210)+(1))|0);
4972 + $x=$211;
4973 + label=45;break;
4974 + case 45:
4975 + var $213=$prevline;
4976 + var $214=($213|0)==0;
4977 + if($214){label=46;break;}else{label=57;break;}
4978 + case 46:
4979 + label=47;break;
4980 + case 47:
4981 + var $217=$count;
4982 + var $218=$217&-8;
4983 + var $219=($218|0)!=0;
4984 + if($219){label=48;break;}else{var $226=0;label=49;break;}
4985 + case 48:
4986 + var $221=$x;
4987 + var $222=((($221)+(8))|0);
4988 + var $223=$3;
4989 + var $224=($222|0)<($223|0);
4990 + var $226=$224;label=49;break;
4991 + case 49:
4992 + var $226;
4993 + if($226){label=50;break;}else{label=51;break;}
4994 + case 50:
4995 + var $228=$x;
4996 + var $229=$line;
4997 + var $230=(($229+($228<<1))|0);
4998 + HEAP16[(($230)>>1)]=0;
4999 + var $231=$count;

This file is too large to show in full.

rdp/core/type.js new
+488
@@ -0,0 +1,488 @@
1 +/*
2 + * Copyright (c) 2014-2015 Sylvain Peyrefitte
3 + *
4 + * This file is part of node-rdpjs.
5 + *
6 + * node-rdpjs is free software: you can redistribute it and/or modify
7 + * it under the terms of the GNU General Public License as published by
8 + * the Free Software Foundation, either version 3 of the License, or
9 + * (at your option) any later version.
10 + *
11 + * This program is distributed in the hope that it will be useful,
12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 + * GNU General Public License for more details.
15 + *
16 + * You should have received a copy of the GNU General Public License
17 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 + */
19 +
20 +var inherits = require('util').inherits;
21 +var log = require('./log');
22 +var error = require('./error');
23 +
24 +/**
25 + * Stream wrapper around buffer type
26 + * @param i {Buffer | integer} size of init buffer
27 + * @returns
28 + */
29 +function Stream(i) {
30 + this.offset = 0;
31 + if (i instanceof Buffer) {
32 + this.buffer = i;
33 + }
34 + else {
35 + this.buffer = Buffer.alloc(i || 8192);
36 + }
37 +}
38 +
39 +/**
40 + * Return length of available data in stream
41 + * @returns {Number} length of available data in stream
42 + */
43 +Stream.prototype.availableLength = function() {
44 + return this.buffer.length - this.offset;
45 +};
46 +
47 +/**
48 + * increment offset
49 + * @param length {integer} length of padding
50 + */
51 +Stream.prototype.readPadding = function(length) {
52 + this.offset += length;
53 +};
54 +
55 +/**
56 + * Format string buffer
57 + * @returns {string} buffer stringified
58 + */
59 +Stream.prototype.getValue = function() {
60 + return this.buffer;
61 +};
62 +
63 +/**
64 + * @param value {object | function} inner value
65 + * @returns
66 + */
67 +function CallableValue(value) {
68 + if(value) {
69 + this.value = value;
70 + }
71 +}
72 +
73 +/**
74 + * For syntaxic purpose
75 + */
76 +Object.defineProperty(CallableValue.prototype, "value", {
77 + get: function() { return this._value(); },
78 + set: function(e) {
79 + if(typeof e !== 'function') {
80 + this._value = function () { return e; };
81 + }
82 + else {
83 + this._value = e;
84 + }
85 + }
86 +});
87 +
88 +/**
89 + * Type readable or writable by binary stream
90 + * @param {object} opt
91 + * .conditional {boolean} read or write type depend on conditional call
92 + * @returns
93 + */
94 +function Type(opt) {
95 + CallableValue.call(this);
96 + this.opt = opt || {};
97 + this.isReaded = false;
98 + this.isWritten = false;
99 +}
100 +
101 +inherits(Type, CallableValue);
102 +
103 +/**
104 + * Write type into binary stream s
105 + * @param {type.Stream} s binary stream
106 + */
107 +Type.prototype.write = function(s) {
108 + //do not write false conditional type
109 + if(this.opt.conditional && !this.opt.conditional())
110 + return this;
111 +
112 + this.isWritten = true;
113 +
114 + this.writeValue(s);
115 + return this;
116 +};
117 +
118 +/**
119 + * Read type from binary stream
120 + * @param {type.Stream} s binary stream
121 + * @returns this to chain call
122 + */
123 +Type.prototype.read = function(s) {
124 + //do not read false conditional type
125 + if(this.opt.conditional && !this.opt.conditional())
126 + return this;
127 +
128 + if(this.opt.optional && s.availableLength() < this.size())
129 + return this;
130 +
131 + this.isReaded = true;
132 +
133 + //constant case
134 + if(this.opt.constant) {
135 + var oldValue = this.value;
136 + try {
137 + this.readValue(s);
138 + }
139 + catch(e) {
140 + if (e instanceof RangeError) {
141 + throw new error.ProtocolError("NODE_RDP_CORE_TYPE_STREAM_TOO_SMALL");
142 + }
143 + throw e;
144 + }
145 +
146 + if(oldValue !== this.value) {
147 + log.error('constant value mismatch ' + oldValue + ' != ' + this.value);
148 + throw new error.ProtocolError("NODE_RDP_CORE_TYPE_CONSTANT_VALUE_MISMATCH");
149 + }
150 + }
151 + else {
152 + try {
153 + this.readValue(s);
154 + }
155 + catch(e) {
156 + if (e instanceof RangeError) {
157 + throw new error.ProtocolError("NODE_RDP_CORE_TYPE_STREAM_TOO_SMALL");
158 + }
159 + throw e;
160 + }
161 + }
162 +
163 + return this;
164 +};
165 +
166 +/**
167 + * Size of type
168 + * @returns {int} Size of type
169 + */
170 +Type.prototype.size = function() {
171 + if(this.opt.conditional && !this.opt.conditional())
172 + return 0;
173 + return this._size_();
174 +};
175 +
176 +/**
177 + * Convert type to stream
178 + * Usefull when you want to buffer
179 + * @returns {Stream}
180 + */
181 +Type.prototype.toStream = function() {
182 + var result = new Stream(this.size());
183 + this.write(result);
184 + return result;
185 +};
186 +
187 +/**
188 + * Node of Raw types
189 + * @param {object} obj composite object
190 + * @param {object} opt Type parameters
191 + */
192 +function Component(obj, opt) {
193 + Type.call(this, opt);
194 + this.obj = obj;
195 +}
196 +
197 +//inherit from type
198 +inherits(Component, Type);
199 +
200 +/**
201 + * ignore criterion
202 + * @param i {string} index name in obj
203 + * @returns {Boolean} true if can be ignore
204 + */
205 +Component.prototype.ignore = function(i) {
206 + // ignore meta information
207 + if(i.lastIndexOf("__", 0) === 0) {
208 + return true;
209 + }
210 + // ignore function
211 + if(typeof(this.obj[i]) === 'function') {
212 + return true;
213 + }
214 + return false;
215 +};
216 +
217 +/**
218 + * Write each sub type into stream
219 + * @param {Stream} s
220 + */
221 +Component.prototype.writeValue = function(s) {
222 + for(var i in this.obj) {
223 + if(this.ignore(i)) {
224 + continue;
225 + }
226 + try {
227 + this.obj[i].write(s);
228 + }
229 + catch(e) {
230 + log.info('during write of field ' + i);
231 + throw e;
232 + }
233 + }
234 +};
235 +
236 +/**
237 + * Read each sub type into stream
238 + * @param {Stream} s from read stream
239 + */
240 +Component.prototype.readValue = function(s) {
241 + var readStream = s;
242 + if(this.opt.readLength) {
243 + readStream = new Stream(s.buffer.slice(s.offset, s.offset + this.opt.readLength.value));
244 + }
245 +
246 + for(var i in this.obj) {
247 + // ignore meta information
248 + if(this.ignore(i)) {
249 + continue;
250 + }
251 + try {
252 + this.obj[i].read(readStream);
253 + }
254 + catch(e) {
255 + log.info('during read of field ' + i);
256 + throw e;
257 + }
258 + }
259 +
260 + // padding
261 + if (this.opt.readLength) {
262 + s.offset += this.opt.readLength.value;
263 + if (readStream.offset < this.opt.readLength.value) {
264 + log.debug('still have available data : read it as padding');
265 + }
266 + }
267 +};
268 +
269 +/**
270 + * Sum size of sub types
271 + */
272 +Component.prototype._size_ = function() {
273 + var size = 0;
274 + for(var i in this.obj) {
275 + if(this.ignore(i)) {
276 + continue;
277 + }
278 + size += this.obj[i].size();
279 + }
280 + return size;
281 +};
282 +
283 +/**
284 + * Leaf of tree type
285 + * @param {number} value of type
286 + * @param {function} readBufferCallback Buffer prototype read function
287 + * @param {function} writeBufferCallback Buffer prototype write function
288 + * @param {object} opt Type parameter
289 + */
290 +function SingleType(value, nbBytes, readBufferCallback, writeBufferCallback, opt){
291 + Type.call(this, opt);
292 + this.value = value || 0;
293 + this.nbBytes = nbBytes;
294 + this.readBufferCallback = readBufferCallback;
295 + this.writeBufferCallback = writeBufferCallback;
296 +}
297 +
298 +//inherit from type
299 +inherits(SingleType, Type);
300 +
301 +/**
302 + * Write SingleType value into stream
303 + * @param s
304 + */
305 +SingleType.prototype.writeValue = function(s) {
306 + this.writeBufferCallback.call(s.buffer, this.value, s.offset);
307 + s.offset += this._size_();
308 +};
309 +
310 +/**
311 + * Read SingleType value into stream
312 + * @param {Stream} s from read stream
313 + */
314 +SingleType.prototype.readValue = function(s) {
315 + this.value = this.readBufferCallback.call(s.buffer, s.offset);
316 + s.offset += this._size_();
317 +};
318 +
319 +/**
320 + * Size of single type
321 + * @returns Size of single type
322 + */
323 +SingleType.prototype._size_ = function() {
324 + return this.nbBytes;
325 +};
326 +
327 +/**
328 + * Integer on 1 byte
329 + * @param {number | function} value of type
330 + * @param {object} opt Type parameter
331 + * @returns
332 + */
333 +function UInt8(value, opt) {
334 + SingleType.call(this, value, 1, Buffer.prototype.readUInt8, Buffer.prototype.writeUInt8, opt);
335 +}
336 +
337 +//inherit from type
338 +inherits(UInt8, SingleType);
339 +
340 +/**
341 + * Integer on 2 bytes in Little Endian
342 + * @param {number | function} value to write or compare if constant
343 + * @param {object} opt Type parameter
344 + * @returns
345 + */
346 +function UInt16Le(value, opt) {
347 + SingleType.call(this, value, 2, Buffer.prototype.readUInt16LE, Buffer.prototype.writeUInt16LE, opt);
348 +}
349 +
350 +//inherit from type
351 +inherits(UInt16Le, SingleType);
352 +
353 +/**
354 + * Integer on 2 bytes in Big Endian
355 + * @param {number | function} value to write or compare if constant
356 + * @param {object} opt Type parameter
357 + * @returns
358 + */
359 +function UInt16Be(value, opt) {
360 + SingleType.call(this, value, 2, Buffer.prototype.readUInt16BE, Buffer.prototype.writeUInt16BE, opt);
361 +}
362 +
363 +//inherit from type
364 +inherits(UInt16Be, SingleType);
365 +
366 +/**
367 + * Integer on 4 bytes in Little Endian
368 + * @param {number | function} value to write or compare if constant
369 + * @param {object} opt Type parameter
370 + * @returns
371 + */
372 +function UInt32Le(value, opt) {
373 + SingleType.call(this, value, 4, Buffer.prototype.readUInt32LE, Buffer.prototype.writeUInt32LE, opt);
374 +}
375 +
376 +//inherit from type
377 +inherits(UInt32Le, SingleType);
378 +
379 +/**
380 + * Integer on 4 bytes in Big Endian
381 + * @param {number | function} value to write or compare if constant
382 + * @param {object} opt Type parameter
383 + * @returns
384 + */
385 +function UInt32Be(value, opt) {
386 + SingleType.call(this, value, 4, Buffer.prototype.readUInt32BE, Buffer.prototype.writeUInt32BE, opt);
387 +}
388 +
389 +//inherit from type
390 +inherits(UInt32Be, SingleType);
391 +
392 +/**
393 + * @param value {Buffer} javascript source string
394 + * @param opt {object} type options
395 + * .readLength {type} length for reading operation
396 + * @returns {type.BinaryString}
397 + */
398 +function BinaryString(value, opt) {
399 + Type.call(this, opt);
400 + this.value = value || Buffer.alloc(0);
401 +}
402 +
403 +//inherit from type
404 +inherits(BinaryString, Type);
405 +
406 +/**
407 + * Write value into string
408 + * @param s {type.Stream}
409 + */
410 +BinaryString.prototype.writeValue = function(s) {
411 + this.value.copy(s.buffer, s.offset);
412 + s.offset += this._size_();
413 +};
414 +
415 +/**
416 + * Read string from offset to read length if specified or end of stream
417 + * @param s {type.Stream}
418 + */
419 +BinaryString.prototype.readValue = function(s) {
420 + if(this.opt.readLength) {
421 + this.value = s.buffer.slice(s.offset, s.offset + this.opt.readLength.value);
422 + }
423 + else {
424 + this.value = s.buffer.slice(s.offset);
425 + }
426 + s.offset += this._size_();
427 +};
428 +
429 +/**
430 + * @returns {integer} length of string
431 + */
432 +BinaryString.prototype._size_ = function() {
433 + return this.value.length;
434 +};
435 +
436 +/**
437 + * Dynamic built type depend on factory function
438 + * @param message {object} parent object
439 + * @param field {string} name of object field
440 + * @param factory {function} factory use to built new type
441 + * @param opt {object} type options
442 + */
443 +function Factory(factory, opt) {
444 + Type.call(this, opt);
445 + this.factory = factory;
446 +}
447 +
448 +//inherit from type
449 +inherits(Factory, Type);
450 +
451 +/**
452 + * build type and write into stream
453 + * @param s {Stream} input stream
454 + */
455 +Factory.prototype.writeValue = function(s) {
456 + this.factory(s);
457 +};
458 +
459 +/**
460 + * build type and read from stream
461 + * @param s {Stream} input stream
462 + */
463 +Factory.prototype.readValue = function(s) {
464 + this.factory(s);
465 +};
466 +
467 +/**
468 + * must be never called
469 + */
470 +Factory.prototype._size_ = function() {
471 + throw new error.FatalError('NODE_RDP_CORE_TYPE_FACTORY_TYPE_HAVE_NO_SIZE');
472 +};
473 +
474 +/**
475 + * Module exports
476 + */
477 +module.exports = {
478 + Stream : Stream,
479 + Component : Component,
480 + UInt8 : UInt8,
481 + UInt16Le : UInt16Le,
482 + UInt16Be : UInt16Be,
483 + UInt32Le : UInt32Le,
484 + UInt32Be : UInt32Be,
485 + BinaryString : BinaryString,
486 + CallableValue : CallableValue,
487 + Factory : Factory
488 +};
\ No newline at end of file
rdp/index.js new
+24
@@ -0,0 +1,24 @@
1 +/*
2 + * Copyright (c) 2014-2015 Sylvain Peyrefitte
3 + *
4 + * This file is part of node-rdpjs.
5 + *
6 + * node-rdpjs is free software: you can redistribute it and/or modify
7 + * it under the terms of the GNU General Public License as published by
8 + * the Free Software Foundation, either version 3 of the License, or
9 + * (at your option) any later version.
10 + *
11 + * This program is distributed in the hope that it will be useful,
12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 + * GNU General Public License for more details.
15 + *
16 + * You should have received a copy of the GNU General Public License
17 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 + */
19 +
20 +var protocol = require('./protocol');
21 +module.exports = {
22 + createClient : protocol.rdp.createClient,
23 + createServer : protocol.rdp.createServer
24 +};
rdp/protocol/cert.js new
+175
@@ -0,0 +1,175 @@
1 +/*
2 + * Copyright (c) 2014-2015 Sylvain Peyrefitte
3 + *
4 + * This file is part of node-rdpjs.
5 + *
6 + * node-rdpjs is free software: you can redistribute it and/or modify
7 + * it under the terms of the GNU General Public License as published by
8 + * the Free Software Foundation, either version 3 of the License, or
9 + * (at your option) any later version.
10 + *
11 + * This program is distributed in the hope that it will be useful,
12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 + * GNU General Public License for more details.
15 + *
16 + * You should have received a copy of the GNU General Public License
17 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 + */
19 +
20 +var type = require('../core').type;
21 +var log = require('../core').log;
22 +var x509 = require('../security').x509;
23 +var rsa = require('../security').rsa;
24 +var asn1 = require('../asn1');
25 +
26 +/**
27 + *  @see http://msdn.microsoft.com/en-us/library/cc240521.aspx
28 + */
29 +var CertificateType = {
30 + CERT_CHAIN_VERSION_1 : 0x00000001,
31 + CERT_CHAIN_VERSION_2 : 0x00000002
32 +};
33 +
34 +/**
35 + * @see http://msdn.microsoft.com/en-us/library/cc240520.aspx
36 + * @returns
37 + */
38 +function rsaPublicKey(opt) {
39 + var self = {
40 + magic : new type.UInt32Le(0x31415352, { constant : true }),
41 + keylen : new type.UInt32Le(function() {
42 + return self.modulus.size() + self.paddinf.size();
43 + }),
44 + bitlen : new type.UInt32Le(function() {
45 + return (self.keylen.value - 8) * 8;
46 + }),
47 + datalen : new type.UInt32Le(function() {
48 + return (self.bitlen.value / 8) - 1;
49 + }),
50 + pubExp : new type.UInt32Le(),
51 + modulus : new type.BinaryString(null, { readLength : new type.CallableValue(function() {
52 + return self.keylen.value - 8;
53 + }) }),
54 + padding : new type.BinaryString(Buffer.from(Array(8 + 1).join('\x00')), { readLength : new type.CallableValue(8) })
55 + };
56 +
57 + return new type.Component(self, opt);
58 +}
59 +
60 +/**
61 + * http://msdn.microsoft.com/en-us/library/cc240519.aspx
62 + * @returns {type.Component}
63 + */
64 +function proprietaryCertificate() {
65 + var self = {
66 + __TYPE__ : CertificateType.CERT_CHAIN_VERSION_1,
67 + dwSigAlgId : new type.UInt32Le(0x00000001, { constant : true }),
68 + dwKeyAlgId : new type.UInt32Le(0x00000001, { constant : true }),
69 + wPublicKeyBlobType : new type.UInt16Le(0x0006, { constant : true }),
70 + wPublicKeyBlobLen : new type.UInt16Le(function() {
71 + return self.PublicKeyBlob.size();
72 + }),
73 + PublicKeyBlob : rsaPublicKey({ readLength : new type.CallableValue(function() {
74 + return self.wPublicKeyBlobLen.value;
75 + }) }),
76 + wSignatureBlobType : new type.UInt16Le(0x0008, { constant : true }),
77 + wSignatureBlobLen : new type.UInt16Le(function() {
78 + return self.SignatureBlob.size() + self.padding.size();
79 + }),
80 + SignatureBlob : new type.BinaryString(null, { readLength : new type.CallableValue(function() {
81 + return self.wSignatureBlobLen.value - self.padding.size;
82 + }) }),
83 + padding : new type.BinaryString(Array(8 + 1).join('\x00'), { readLength : new type.CallableValue(8) }),
84 + /**
85 + * @return {object} rsa.publicKey
86 + */
87 + getPublicKey : function() {
88 + return rsa.publicKey(self.PublicKeyBlob.obj.modulus.value, self.PublicKeyBlob.obj.pubExp.value);
89 + }
90 + };
91 +
92 + return new type.Component(self);
93 +}
94 +
95 +/**
96 + * For x509 certificate
97 + * @see http://msdn.microsoft.com/en-us/library/cc241911.aspx
98 + * @returns {type.Component}
99 + */
100 +function certBlob() {
101 + var self = {
102 + cbCert : new type.UInt32Le(function() {
103 + return self.abCert.size();
104 + }),
105 + abCert : new type.BinaryString(null, { readLength : new type.CallableValue(function() {
106 + return self.cbCert.value;
107 + }) })
108 + };
109 +
110 + return new type.Component(self);
111 +}
112 +
113 +/**
114 + * x509 certificate chain
115 + * @see http://msdn.microsoft.com/en-us/library/cc241910.aspx
116 + * @returns {type.Component}
117 + */
118 +function x509CertificateChain() {
119 + var self = {
120 + __TYPE__ : CertificateType.CERT_CHAIN_VERSION_2,
121 + NumCertBlobs : new type.UInt32Le(),
122 + CertBlobArray : new type.Factory(function(s) {
123 + self.CertBlobArray = new type.Component([]);
124 + for(var i = 0; i < self.NumCertBlobs.value; i++) {
125 + self.CertBlobArray.obj.push(certBlob().read(s));
126 + }
127 + }),
128 + padding : new type.BinaryString(null, { readLength : new type.CallableValue(function() {
129 + return 8 + 4 * self.NumCertBlobs.value;
130 + }) }),
131 + /**
132 + * @return {object} {n : modulus{bignum}, e : publicexponent{integer}
133 + */
134 + getPublicKey : function(){
135 + var cert = x509.X509Certificate().decode(new type.Stream(self.CertBlobArray.obj[self.CertBlobArray.obj.length - 1].obj.abCert.value), asn1.ber);
136 + var publikeyStream = new type.Stream(cert.value.tbsCertificate.value.subjectPublicKeyInfo.value.subjectPublicKey.toBuffer());
137 + var asn1PublicKey = x509.RSAPublicKey().decode(publikeyStream, asn1.ber);
138 + return rsa.publicKey(asn1PublicKey.value.modulus.value, asn1PublicKey.value.publicExponent.value);
139 + }
140 + };
141 +
142 + return new type.Component(self);
143 +}
144 +
145 +function certificate() {
146 + var self = {
147 + dwVersion : new type.UInt32Le(function() {
148 + return self.certData.__TYPE__;
149 + }),
150 + certData : new type.Factory(function(s) {
151 + switch(self.dwVersion.value & 0x7fffffff) {
152 + case CertificateType.CERT_CHAIN_VERSION_1:
153 + log.debug('read proprietary certificate');
154 + self.certData = proprietaryCertificate().read(s);
155 + break;
156 + case CertificateType.CERT_CHAIN_VERSION_2:
157 + log.debug('read x.509 certificate chain');
158 + self.certData = x509CertificateChain().read(s);
159 + break;
160 + default:
161 + log.error('unknown cert type ' + self.dwVersion.value & 0x7fffffff);
162 + }
163 + })
164 + };
165 +
166 + return new type.Component(self);
167 +}
168 +
169 +/**
170 + * Module exports
171 + */
172 +module.exports = {
173 + CertificateType : CertificateType,
174 + certificate : certificate
175 +};
\ No newline at end of file
rdp/protocol/index.js new
+30
@@ -0,0 +1,30 @@
1 +/*
2 + * Copyright (c) 2014-2015 Sylvain Peyrefitte
3 + *
4 + * This file is part of node-rdpjs.
5 + *
6 + * node-rdpjs is free software: you can redistribute it and/or modify
7 + * it under the terms of the GNU General Public License as published by
8 + * the Free Software Foundation, either version 3 of the License, or
9 + * (at your option) any later version.
10 + *
11 + * This program is distributed in the hope that it will be useful,
12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 + * GNU General Public License for more details.
15 + *
16 + * You should have received a copy of the GNU General Public License
17 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 + */
19 +
20 +var TPKT = require('./tpkt');
21 +var x224 = require('./x224');
22 +var t125 = require('./t125');
23 +var rdp = require('./rdp');
24 +
25 +module.exports = {
26 + TPKT : TPKT,
27 + x224 : x224,
28 + t125 : t125,
29 + rdp : rdp
30 +};
rdp/protocol/nla.js renamed
+341 -35
@@ -1,8 +1,223 @@
1 +const inherits = require('util').inherits;
2 +const type = require('../core').type;
3 +const events = require('events');
4 const crypto = require('crypto');
5 const forge = require('node-forge');
6 const asn1 = forge.asn1;
7 const pki = forge.pki;
8
9 +/**
10 + * NLA layer of rdp stack
11 + */
12 +function NLA(transport, nlaCompletedFunc, domain, user, password) {
13 + // Get NTLM ready
14 + const ntlm = Create_Ntlm();
15 + ntlm.domain = domain;
16 + ntlm.completedFunc = nlaCompletedFunc;
17 + ntlm.user = user;
18 + ntlm.password = password;
19 + ntlm.response_key_nt = ntowfv2(ntlm.password, ntlm.user, ntlm.domain);
20 + ntlm.response_key_lm = lmowfv2(ntlm.password, ntlm.user, ntlm.domain);
21 + this.ntlm = ntlm;
22 + this.state = 1;
23 +
24 + // Get transport ready
25 + this.transport = transport;
26 + // Wait 2 bytes
27 + this.transport.expect(2);
28 + // Next state is receive header
29 + var self = this;
30 +
31 + this.oldDataListeners = this.transport.listeners('data');
32 + this.oldCloseListeners = this.transport.listeners('close');
33 + this.oldErrorListeners = this.transport.listeners('error');
34 +
35 + // Unhook the previous transport handler
36 + this.transport.removeAllListeners('data');
37 + this.transport.removeAllListeners('close');
38 + this.transport.removeAllListeners('error');
39 +
40 + // Hook this module as the transport handler
41 + this.transport.once('data', function (s) {
42 + self.recvHeader(s);
43 + }).on('close', function () {
44 + self.emit('close');
45 + }).on('error', function (err) {
46 + self.emit('close'); // Errors occur when NLA authentication fails, for now, just close.
47 + //self.emit('error', err);
48 + });
49 +}
50 +
51 +/**
52 + * inherit from a packet layer
53 + */
54 +inherits(NLA, events.EventEmitter);
55 +
56 +/**
57 + * Receive correct packet as expected
58 + * @param s {type.Stream}
59 + */
60 +NLA.prototype.recvHeader = function (s) {
61 + //console.log('NLA - recvHeader', s);
62 + var self = this;
63 + var derType = new type.UInt8().read(s).value;
64 + var derLen = new type.UInt8().read(s).value;
65 + self.buffers = [ s.buffer ];
66 +
67 + if (derLen < 128) {
68 + // wait for the entire data block
69 + this.transport.expect(derLen);
70 + this.transport.once('data', function (s) { self.recvData(s); });
71 + } else {
72 + // wait for the header size
73 + this.transport.expect(derLen - 128);
74 + this.transport.once('data', function (s) { self.recvHeaderSize(s); });
75 + }
76 +
77 + //console.log('NLA - DER', derType, derLen);
78 +};
79 +
80 +/**
81 + * Receive correct packet as expected
82 + * @param s {type.Stream}
83 + */
84 +NLA.prototype.recvHeaderSize = function (s) {
85 + //console.log('NLA - recvHeaderSize', s.buffer.length);
86 + var self = this;
87 + self.buffers.push(s.buffer);
88 + if (s.buffer.length == 1) {
89 + // wait for the entire data block
90 + var derLen = s.buffer.readUInt8(0);
91 + this.transport.expect(derLen);
92 + this.transport.once('data', function (s) { self.recvData(s); });
93 + } else if (s.buffer.length == 2) {
94 + // wait for the entire data block
95 + var derLen = s.buffer.readUInt16BE(0);
96 + this.transport.expect(derLen);
97 + this.transport.once('data', function (s) { self.recvData(s); });
98 + }
99 +}
100 +
101 +/**
102 + * Receive correct packet as expected
103 + * @param s {type.Stream}
104 + */
105 +NLA.prototype.recvData = function (s) {
106 + //console.log('NLA - recvData', s.buffer.length);
107 + var self = this;
108 + self.buffers.push(s.buffer);
109 + var entireBuffer = Buffer.concat(self.buffers);
110 + //console.log('entireBuffer', entireBuffer.toString('hex'));
111 +
112 + // We have a full ASN1 data block, decode it now
113 + const der = asn1.fromDer(entireBuffer.toString('binary'));
114 + const derNum = der.value[0].value[0].value.charCodeAt(0);
115 + //console.log('NLA - Number', derNum);
116 +
117 + if (derNum == 6) {
118 + if (this.state == 1) {
119 + const derBuffer = Buffer.from(der.value[1].value[0].value[0].value[0].value[0].value, 'binary');
120 + const client_challenge = read_challenge_message(this.ntlm, derBuffer);
121 + self.security_interface = build_security_interface(this.ntlm);
122 + const peer_cert = this.transport.secureSocket.getPeerCertificate();
123 + const challenge = create_ts_authenticate(client_challenge, self.security_interface.gss_wrapex(peer_cert.pubkey.slice(24)));
124 + this.ntlm.publicKeyDer = peer_cert.pubkey.slice(24);
125 + this.send(challenge);
126 + this.state = 2;
127 + } else if (this.state == 2) {
128 + const derBuffer = Buffer.from(der.value[1].value[0].value, 'binary');
129 + const publicKeyDer = self.security_interface.gss_unwrapex(derBuffer);
130 +
131 + // Check that the public key is identical except the first byte which is the DER encoding type.
132 + if (!this.ntlm.publicKeyDer.slice(1).equals(publicKeyDer.slice(1))) { console.log('RDP man-in-the-middle detected.'); close(); return; }
133 + delete this.ntlm.publicKeyDer; // Clean this up, we don't need it anymore.
134 +
135 + var xdomain, xuser, xpassword;
136 + if (this.ntlm.is_unicode) {
137 + xdomain = toUnicode(this.ntlm.domain);
138 + xuser = toUnicode(this.ntlm.user);
139 + xpassword = toUnicode(this.ntlm.password);
140 + } else {
141 + xdomain = Buffer.from(this.ntlm.domain, 'utf8');
142 + xuser = Buffer.from(this.ntlm.user, 'utf8');
143 + xpassword = Buffer.from(this.ntlm.password, 'utf8');
144 + }
145 +
146 + const credentials = create_ts_authinfo(self.security_interface.gss_wrapex(create_ts_credentials(xdomain, xuser, xpassword)));
147 + this.send(credentials);
148 +
149 + // Rehook the previous transport handler
150 + this.transport.removeAllListeners('data');
151 + this.transport.removeAllListeners('close');
152 + this.transport.removeAllListeners('error');
153 +
154 + for (var i in this.oldDataListeners) { this.transport.once('data', this.oldDataListeners[i]); }
155 + for (var i in this.oldCloseListeners) { this.transport.on('close', this.oldCloseListeners[i]); }
156 + for (var i in this.oldErrorListeners) { this.transport.on('error', this.oldErrorListeners[i]); }
157 +
158 + // Done!
159 + this.transport.expect(2);
160 + this.state = 3;
161 + this.ntlm.completedFunc();
162 + return;
163 + }
164 + }
165 +
166 + // Receive next block of data
167 + this.transport.expect(2);
168 + this.transport.once('data', function (s) { self.recvHeader(s); });
169 +}
170 +
171 +
172 +/**
173 + * Send message throught NLA layer
174 + * @param message {type.*}
175 + */
176 +NLA.prototype.send = function (message) {
177 + this.transport.sendBuffer(message);
178 +};
179 +
180 +/**
181 + * close stack
182 + */
183 +NLA.prototype.close = function() {
184 + this.transport.close();
185 +};
186 +
187 +
188 +NLA.prototype.sendNegotiateMessage = function () {
189 + // Create create_ts_request
190 + this.ntlm.negotiate_message = create_negotiate_message();
191 + const asn1obj =
192 + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
193 + asn1.create(asn1.Class.CONTEXT_SPECIFIC, 0, true, [
194 + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false, asn1.integerToDer(2)),
195 + ]),
196 + asn1.create(asn1.Class.CONTEXT_SPECIFIC, 1, true, [
197 + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
198 + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
199 + asn1.create(asn1.Class.CONTEXT_SPECIFIC, 0, true, [
200 + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false, this.ntlm.negotiate_message.toString('binary'))
201 + ])
202 + ])
203 + ])
204 + ])
205 + ]);
206 +
207 + // Serialize an ASN.1 object to DER format
208 + this.send(Buffer.from(asn1.toDer(asn1obj).data, 'binary'));
209 +}
210 +
211 +/**
212 + * Module exports
213 + */
214 +module.exports = NLA;
215 +
216 +
217 +
218 +
219 +
220 +
221 const NegotiateFlags = {
222 NtlmsspNegociate56: 0x80000000,
223 NtlmsspNegociateKeyExch: 0x40000000,
@@ -171,10 +386,10 @@ function build_security_interface(ntlm) {
386 const encrypted_data = obj.encrypt.update(data);
387 const signature = mac(obj.encrypt, obj.signing_key, obj.seq_num, data);
388 obj.seq_num++;
174 - return Buffer.concat([ signature, encrypted_data ] );
389 + return Buffer.concat([signature, encrypted_data]);
390 }
391
177 - obj.gss_unwrapex = function(data) {
392 + obj.gss_unwrapex = function (data) {
393 const version = data.readInt32LE(0);
394 const checksum = data.slice(4, 12);
395 const seqnum = data.readInt32LE(12);
@@ -183,9 +398,9 @@ function build_security_interface(ntlm) {
398 const plaintext_checksum = obj.decrypt.update(checksum);
399 const seqnumbuf = Buffer.alloc(4);
400 seqnumbuf.writeInt32LE(seqnum, 0);
186 - const computed_checksum = hmac_md5(obj.verify_key, Buffer.concat([ seqnumbuf, plaintext_payload ])).slice(0, 8);
401 + const computed_checksum = hmac_md5(obj.verify_key, Buffer.concat([seqnumbuf, plaintext_payload])).slice(0, 8);
402 if (!plaintext_checksum.equals(computed_checksum)) { console.log("Invalid checksum on NTLMv2"); }
188 - return plaintext_payload.toString();
403 + return plaintext_payload;
404 }
405
406 return obj;
@@ -220,19 +435,19 @@ function authenticate_message(lm_challenge_response, nt_challenge_response, doma
435 buf.writeInt32LE(3, 8); // MessageType
436 buf.writeInt16LE(lm_challenge_response.length, 12); // LmChallengeResponseLen
437 buf.writeInt16LE(lm_challenge_response.length, 14); // LmChallengeResponseMaxLen
223 - if (lm_challenge_response.length > 0) { buf.writeInt32LE(offset, 16); } // LmChallengeResponseBufferOffset
438 + buf.writeInt32LE(offset, 16); // LmChallengeResponseBufferOffset
439 buf.writeInt16LE(nt_challenge_response.length, 20); // NtChallengeResponseLen
440 buf.writeInt16LE(nt_challenge_response.length, 22); // NtChallengeResponseMaxLen
226 - if (nt_challenge_response.length > 0) { buf.writeInt32LE(offset + lm_challenge_response.length, 24); } // NtChallengeResponseBufferOffset
441 + buf.writeInt32LE(offset + lm_challenge_response.length, 24); // NtChallengeResponseBufferOffset
442 buf.writeInt16LE(domain.length, 28); // DomainNameLen
443 buf.writeInt16LE(domain.length, 30); // DomainNameMaxLen
229 - if (domain.length > 0) { buf.writeInt32LE(offset + lm_challenge_response.length + nt_challenge_response.length, 32); } // DomainNameBufferOffset
444 + buf.writeInt32LE(offset + lm_challenge_response.length + nt_challenge_response.length, 32); // DomainNameBufferOffset
445 buf.writeInt16LE(user.length, 36); // UserNameLen
446 buf.writeInt16LE(user.length, 38); // UserNameMaxLen
232 - if (user.length > 0) { buf.writeInt32LE(offset + lm_challenge_response.length + nt_challenge_response.length + domain.length, 40); } // UserNameBufferOffset
447 + buf.writeInt32LE(offset + lm_challenge_response.length + nt_challenge_response.length + domain.length, 40); // UserNameBufferOffset
448 buf.writeInt16LE(workstation.length, 44); // WorkstationLen
449 buf.writeInt16LE(workstation.length, 46); // WorkstationMaxLen
235 - if (workstation.length > 0) { buf.writeInt32LE(offset + lm_challenge_response.length + nt_challenge_response.length + domain.length + user.length, 48); } // WorkstationBufferOffset
450 + buf.writeInt32LE(offset + lm_challenge_response.length + nt_challenge_response.length + domain.length + user.length, 48); // WorkstationBufferOffset
451 buf.writeInt16LE(encrypted_random_session_key.length, 52); // EncryptedRandomSessionLen
452 buf.writeInt16LE(encrypted_random_session_key.length, 54); // EncryptedRandomSessionMaxLen
453 buf.writeInt32LE(offset + lm_challenge_response.length + nt_challenge_response.length + domain.length + user.length + workstation.length, 56); // EncryptedRandomSessionBufferOffset
@@ -248,7 +463,81 @@ function authenticate_message(lm_challenge_response, nt_challenge_response, doma
463 return [buf, payload];
464 }
465
466 +function create_ts_authinfo(auth_info) {
467 + asn1obj =
468 + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
469 + asn1.create(asn1.Class.CONTEXT_SPECIFIC, 0, true, [
470 + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false, asn1.integerToDer(2)),
471 + ]),
472 + asn1.create(asn1.Class.CONTEXT_SPECIFIC, 2, true, [
473 + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false, auth_info.toString('binary'))
474 + ])
475 + ]);
476 + return Buffer.from(asn1.toDer(asn1obj).data, 'binary');
477 +}
478 +
479 +function create_ts_credentials(domain, user, password) {
480 + var asn1obj =
481 + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
482 + asn1.create(asn1.Class.CONTEXT_SPECIFIC, 0, true, [
483 + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false, domain.toString('binary'))
484 + ]),
485 + asn1.create(asn1.Class.CONTEXT_SPECIFIC, 1, true, [
486 + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false, user.toString('binary'))
487 + ]),
488 + asn1.create(asn1.Class.CONTEXT_SPECIFIC, 2, true, [
489 + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false, password.toString('binary'))
490 + ])
491 + ]);
492 + const ts_password_cred_encoded = asn1.toDer(asn1obj).data;
493 + asn1obj =
494 + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
495 + asn1.create(asn1.Class.CONTEXT_SPECIFIC, 0, true, [
496 + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false, asn1.integerToDer(1)),
497 + ]),
498 + asn1.create(asn1.Class.CONTEXT_SPECIFIC, 1, true, [
499 + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false, ts_password_cred_encoded)
500 + ])
501 + ]);
502 + return Buffer.from(asn1.toDer(asn1obj).data, 'binary');
503 +}
504 +
505 +function create_ts_authenticate(nego, pub_key_auth) {
506 + // Create create_ts_request
507 + const asn1obj =
508 + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
509 + asn1.create(asn1.Class.CONTEXT_SPECIFIC, 0, true, [
510 + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false, asn1.integerToDer(2)),
511 + ]),
512 + asn1.create(asn1.Class.CONTEXT_SPECIFIC, 1, true, [
513 + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
514 + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
515 + asn1.create(asn1.Class.CONTEXT_SPECIFIC, 0, true, [
516 + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false, nego.toString('binary'))
517 + ])
518 + ])
519 + ])
520 + ]),
521 + asn1.create(asn1.Class.CONTEXT_SPECIFIC, 3, true, [
522 + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false, pub_key_auth.toString('binary'))
523 + ]),
524 + ]);
525 +
526 + // Serialize an ASN.1 object to DER format
527 + return Buffer.from(asn1.toDer(asn1obj).data, 'binary');
528 +}
529 +
530 function read_challenge_message(ntlm, derBuffer) {
531 +
532 + //console.log('ntlm.negotiate_message', ntlm.negotiate_message.toString('hex'));
533 + //ntlm.negotiate_message = Buffer.from('4e544c4d53535000010000003582086000000000000000000000000000000000', 'hex');
534 +
535 + // ********
536 + //ntlm.exported_session_key = Buffer.from('9a1ed052e932834a311daf90c2750219', 'hex'); // *************************
537 + //derBuffer = Buffer.from('4e544c4d53535000020000000e000e003800000035828a6259312ef59a4517dd000000000000000058005800460000000a00614a0000000f430045004e005400520041004c0002000e00430045004e005400520041004c0001000e00430045004e005400520041004c0004000e00430065006e007400720061006c0003000e00430065006e007400720061006c00070008007b7b3bee9e5ad80100000000', 'hex');
538 +
539 + //console.log("YST: read_challenge_message1: ", derBuffer.toString('hex'));
540 +
541 const headerSignature = derBuffer.slice(0, 8);
542 if (headerSignature.toString('hex') != '4e544c4d53535000') { console.log('BAD SIGNATURE'); }
543 const messageType = derBuffer.readInt32LE(8);
@@ -264,22 +553,40 @@ function read_challenge_message(ntlm, derBuffer) {
553 const targetInfoLenMax = derBuffer.readInt16LE(42);
554 const targetInfoBufferOffset = derBuffer.readInt32LE(44);
555 const targetName = derBuffer.slice(targetNameBufferOffset, targetNameBufferOffset + targetNameLen);
556 + const targetInfoBuf = derBuffer.slice(targetInfoBufferOffset, targetInfoBufferOffset + targetInfoLen);
557 const targetInfo = decodeTargetInfo(derBuffer.slice(targetInfoBufferOffset, targetInfoBufferOffset + targetInfoLen));
558 const timestamp = targetInfo[7];
559 + //const timestamp = Buffer.from('7b7b3bee9e5ad801', 'hex'); // **************
560 if (timestamp == null) { console.log('NO TIMESTAMP'); }
561 const clientChallenge = crypto.randomBytes(8);
562 + //const clientChallenge = Buffer.from('10aac9679ef64e66', 'hex'); // *****************************
563 const response_key_nt = ntowfv2(ntlm.password, ntlm.user, ntlm.domain); // Password, Username, Domain
564 const response_key_lm = lmowfv2(ntlm.password, ntlm.user, ntlm.domain); // Password, Username, Domain
565
274 - var resp = compute_response_v2(response_key_nt, response_key_lm, serverChallenge, clientChallenge, timestamp, targetName);
566 + //console.log("YST: target_name:", targetInfoBuf.toString('hex'));
567 + //console.log("YST: timestamp:", timestamp.toString('hex'));
568 + //console.log('YST: client_challenge:', clientChallenge.toString('hex'));
569 + //console.log("YST: response_key_nt:", response_key_nt.toString('hex'));
570 + //console.log("YST: response_key_lm:", response_key_lm.toString('hex'));
571 +
572 + var resp = compute_response_v2(response_key_nt, response_key_lm, serverChallenge, clientChallenge, timestamp, targetInfoBuf);
573 const nt_challenge_response = resp[0];
574 const lm_challenge_response = resp[1];
575 const session_base_key = resp[2];
576
577 + //console.log('YST: nt_challenge_response:', nt_challenge_response.toString('hex'));
578 + //console.log('YST: lm_challenge_response:', lm_challenge_response.toString('hex'));
579 + //console.log("YST: session_base_key:", session_base_key.toString('hex'));
580 +
581 const key_exchange_key = kx_key_v2(session_base_key, lm_challenge_response, serverChallenge);
582 const encrypted_random_session_key = rc4k(key_exchange_key, ntlm.exported_session_key);
583
584 + //console.log("YST: key_exchange_key:", key_exchange_key.toString('hex'));
585 + //console.log("YST: self.exported_session_key:", ntlm.exported_session_key.toString('hex'));
586 + //console.log("YST: encrypted_random_session_key:", encrypted_random_session_key.toString('hex'));
587 +
588 ntlm.is_unicode = ((negotiateFlags & 1) != 0)
589 + //console.log("YST: self.is_unicode: {}", ntlm.is_unicode);
590 var xdomain = null;
591 var xuser = null;
592 if (ntlm.is_unicode) {
@@ -290,37 +597,26 @@ function read_challenge_message(ntlm, derBuffer) {
597 xuser = Buffer.from(ntlm.user, 'utf8');
598 }
599
600 + //console.log("YST: domain:", xdomain.toString('hex'));
601 + //console.log("YST: user:", xuser.toString('hex'));
602 +
603 const auth_message_compute = authenticate_message(lm_challenge_response, nt_challenge_response, xdomain, xuser, zeroBuffer(0), encrypted_random_session_key, negotiateFlags);
604
605 // Write a tmp message to compute MIC and then include it into final message
606 const tmp_final_auth_message = Buffer.concat([auth_message_compute[0], zeroBuffer(16), auth_message_compute[1]]);
607
298 - const signature = mic(ntlm.exported_session_key, ntlm.negotiate_message, derBuffer, tmp_final_auth_message);
299 - return Buffer.concat([auth_message_compute[0], signature, auth_message_compute[1]]);
300 -}
301 -
608 + //console.log("YST: tmp_final_auth_message: {}", tmp_final_auth_message.toString('hex'));
609
303 -/*
304 -// Create create_ts_request
305 -
306 -const entireBuffer = Buffer.from('3081b2a003020106a181aa3081a73081a4a081a104819e4e544c4d53535000020000000e000e003800000035828a62f2290572b3cac375000000000000000058005800460000000a00614a0000000f430045004e005400520041004c0002000e00430045004e005400520041004c0001000e00430045004e005400520041004c0004000e00430065006e007400720061006c0003000e00430065006e007400720061006c0007000800afbc2c2a9256d80100000000', 'hex').toString('binary');
610 + const signature = mic(ntlm.exported_session_key, ntlm.negotiate_message, derBuffer, tmp_final_auth_message);
611
308 -const ntml = Create_Ntlm();
309 -ntml.domain = "";
310 -ntml.user = "default";
311 -ntml.password = "";
312 -ntml.negotiate_message = Buffer.from('4e544c4d53535000010000003582086000000000000000000000000000000000', 'hex');
612 + //console.log("YST: signature: {}", signature.toString('hex'));
613
314 -// We have a full ASN1 data block, decode it now
315 -const der = asn1.fromDer(entireBuffer.toString('binary'));
316 -const derNum = der.value[0].value[0].value.charCodeAt(0);
317 -const derBuffer = Buffer.from(der.value[1].value[0].value[0].value[0].value[0].value, 'binary');
318 -const client_challenge = read_challenge_message(ntml, derBuffer);
614 + const r = Buffer.concat([auth_message_compute[0], signature, auth_message_compute[1]]);
615
320 -console.log('client_challenge', client_challenge.toString('hex'));
616 + //console.log("YST: read_challenge_message2: {}", r.toString('hex'));
617
322 -const NTLMv2SecurityInterface = build_security_interface(ntml);
323 -*/
618 + return r;
619 +}
620
621
622 function unitTest() {
@@ -387,9 +683,19 @@ function unitTest() {
683 r = rc4.update(Buffer.from("bar"));
684 console.log(compareArray(bufToArr(r), [201, 67, 159]) ? "RC4 1 passed." : "RC4 1 failed.");
685 r = rc4.update(Buffer.from("bar"));
390 - console.log(compareArray(bufToArr(r), [75, 169, 19]) ? "RC4 2 passed." : "RC4 failed.");
686 + console.log(compareArray(bufToArr(r), [75, 169, 19]) ? "RC4 2 passed." : "RC4 2 failed.");
687
392 - console.log('--- RDP NLA Unit Tests Completed');
393 -}
688 + // Test create_ts_authenticate
689 + r = create_ts_authenticate(Buffer.from("000102", 'hex'), Buffer.from("000102", 'hex'));
690 + console.log(compareArray(bufToArr(r), [48, 25, 160, 3, 2, 1, 2, 161, 11, 48, 9, 48, 7, 160, 5, 4, 3, 0, 1, 2, 163, 5, 4, 3, 0, 1, 2]) ? "create_ts_authenticate passed." : "create_ts_authenticate failed.");
691
395 -unitTest();
692 + // Test test_create_ts_credentials
693 + r = create_ts_credentials(Buffer.from("domain"), Buffer.from("user"), Buffer.from("password"));
694 + console.log(compareArray(bufToArr(r), [48, 41, 160, 3, 2, 1, 1, 161, 34, 4, 32, 48, 30, 160, 8, 4, 6, 100, 111, 109, 97, 105, 110, 161, 6, 4, 4, 117, 115, 101, 114, 162, 10, 4, 8, 112, 97, 115, 115, 119, 111, 114, 100]) ? "test_create_ts_credentials passed." : "test_create_ts_credentials failed.");
695 +
696 + // Test create_ts_authinfo
697 + r = create_ts_authinfo(Buffer.from("foo"));
698 + console.log(compareArray(bufToArr(r), [48, 12, 160, 3, 2, 1, 2, 162, 5, 4, 3, 102, 111, 111]) ? "create_ts_authinfo passed." : "create_ts_authinfo failed.");
699 +
700 + console.log('--- RDP NLA Unit Tests Completed');
701 +}
\ No newline at end of file
rdp/protocol/pdu/caps.js new
+704
@@ -0,0 +1,704 @@
1 +/*
2 + * Copyright (c) 2014-2015 Sylvain Peyrefitte
3 + *
4 + * This file is part of node-rdpjs.
5 + *
6 + * node-rdpjs is free software: you can redistribute it and/or modify
7 + * it under the terms of the GNU General Public License as published by
8 + * the Free Software Foundation, either version 3 of the License, or
9 + * (at your option) any later version.
10 + *
11 + * This program is distributed in the hope that it will be useful,
12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 + * GNU General Public License for more details.
15 + *
16 + * You should have received a copy of the GNU General Public License
17 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 + */
19 +
20 +var type = require('../../core').type;
21 +var log = require('../../core').log;
22 +var error = require('../../core').error;
23 +
24 +/**
25 + * @see http://msdn.microsoft.com/en-us/library/cc240486.aspx
26 + */
27 +var CapsType = {
28 + CAPSTYPE_GENERAL : 0x0001,
29 + CAPSTYPE_BITMAP : 0x0002,
30 + CAPSTYPE_ORDER : 0x0003,
31 + CAPSTYPE_BITMAPCACHE : 0x0004,
32 + CAPSTYPE_CONTROL : 0x0005,
33 + CAPSTYPE_ACTIVATION : 0x0007,
34 + CAPSTYPE_POINTER : 0x0008,
35 + CAPSTYPE_SHARE : 0x0009,
36 + CAPSTYPE_COLORCACHE : 0x000A,
37 + CAPSTYPE_SOUND : 0x000C,
38 + CAPSTYPE_INPUT : 0x000D,
39 + CAPSTYPE_FONT : 0x000E,
40 + CAPSTYPE_BRUSH : 0x000F,
41 + CAPSTYPE_GLYPHCACHE : 0x0010,
42 + CAPSTYPE_OFFSCREENCACHE : 0x0011,
43 + CAPSTYPE_BITMAPCACHE_HOSTSUPPORT : 0x0012,
44 + CAPSTYPE_BITMAPCACHE_REV2 : 0x0013,
45 + CAPSTYPE_VIRTUALCHANNEL : 0x0014,
46 + CAPSTYPE_DRAWNINEGRIDCACHE : 0x0015,
47 + CAPSTYPE_DRAWGDIPLUS : 0x0016,
48 + CAPSTYPE_RAIL : 0x0017,
49 + CAPSTYPE_WINDOW : 0x0018,
50 + CAPSETTYPE_COMPDESK : 0x0019,
51 + CAPSETTYPE_MULTIFRAGMENTUPDATE : 0x001A,
52 + CAPSETTYPE_LARGE_POINTER : 0x001B,
53 + CAPSETTYPE_SURFACE_COMMANDS : 0x001C,
54 + CAPSETTYPE_BITMAP_CODECS : 0x001D,
55 + CAPSSETTYPE_FRAME_ACKNOWLEDGE : 0x001E
56 +};
57 +
58 +/**
59 + * @see http://msdn.microsoft.com/en-us/library/cc240549.aspx
60 + */
61 +var MajorType = {
62 + OSMAJORTYPE_UNSPECIFIED : 0x0000,
63 + OSMAJORTYPE_WINDOWS : 0x0001,
64 + OSMAJORTYPE_OS2 : 0x0002,
65 + OSMAJORTYPE_MACINTOSH : 0x0003,
66 + OSMAJORTYPE_UNIX : 0x0004,
67 + OSMAJORTYPE_IOS : 0x0005,
68 + OSMAJORTYPE_OSX : 0x0006,
69 + OSMAJORTYPE_ANDROID : 0x0007
70 +};
71 +
72 +/**
73 + * @see http://msdn.microsoft.com/en-us/library/cc240549.aspx
74 + */
75 +var MinorType = {
76 + OSMINORTYPE_UNSPECIFIED : 0x0000,
77 + OSMINORTYPE_WINDOWS_31X : 0x0001,
78 + OSMINORTYPE_WINDOWS_95 : 0x0002,
79 + OSMINORTYPE_WINDOWS_NT : 0x0003,
80 + OSMINORTYPE_OS2_V21 : 0x0004,
81 + OSMINORTYPE_POWER_PC : 0x0005,
82 + OSMINORTYPE_MACINTOSH : 0x0006,
83 + OSMINORTYPE_NATIVE_XSERVER : 0x0007,
84 + OSMINORTYPE_PSEUDO_XSERVER : 0x0008,
85 + OSMINORTYPE_WINDOWS_RT : 0x0009
86 +};
87 +
88 +/**
89 + * @see http://msdn.microsoft.com/en-us/library/cc240549.aspx
90 + */
91 +var GeneralExtraFlag = {
92 + FASTPATH_OUTPUT_SUPPORTED : 0x0001,
93 + NO_BITMAP_COMPRESSION_HDR : 0x0400,
94 + LONG_CREDENTIALS_SUPPORTED : 0x0004,
95 + AUTORECONNECT_SUPPORTED : 0x0008,
96 + ENC_SALTED_CHECKSUM : 0x0010
97 +};
98 +
99 +var Boolean = {
100 + FALSE : 0x00,
101 + TRUE : 0x01
102 +};
103 +
104 +/**
105 + * @see http://msdn.microsoft.com/en-us/library/cc240556.aspx
106 + */
107 +var OrderFlag = {
108 + NEGOTIATEORDERSUPPORT : 0x0002,
109 + ZEROBOUNDSDELTASSUPPORT : 0x0008,
110 + COLORINDEXSUPPORT : 0x0020,
111 + SOLIDPATTERNBRUSHONLY : 0x0040,
112 + ORDERFLAGS_EXTRA_FLAGS : 0x0080
113 +};
114 +
115 +/**
116 + * @see http://msdn.microsoft.com/en-us/library/cc240556.aspx
117 + */
118 +var Order = {
119 + TS_NEG_DSTBLT_INDEX : 0x00,
120 + TS_NEG_PATBLT_INDEX : 0x01,
121 + TS_NEG_SCRBLT_INDEX : 0x02,
122 + TS_NEG_MEMBLT_INDEX : 0x03,
123 + TS_NEG_MEM3BLT_INDEX : 0x04,
124 + TS_NEG_DRAWNINEGRID_INDEX : 0x07,
125 + TS_NEG_LINETO_INDEX : 0x08,
126 + TS_NEG_MULTI_DRAWNINEGRID_INDEX : 0x09,
127 + TS_NEG_SAVEBITMAP_INDEX : 0x0B,
128 + TS_NEG_MULTIDSTBLT_INDEX : 0x0F,
129 + TS_NEG_MULTIPATBLT_INDEX : 0x10,
130 + TS_NEG_MULTISCRBLT_INDEX : 0x11,
131 + TS_NEG_MULTIOPAQUERECT_INDEX : 0x12,
132 + TS_NEG_FAST_INDEX_INDEX : 0x13,
133 + TS_NEG_POLYGON_SC_INDEX : 0x14,
134 + TS_NEG_POLYGON_CB_INDEX : 0x15,
135 + TS_NEG_POLYLINE_INDEX : 0x16,
136 + TS_NEG_FAST_GLYPH_INDEX : 0x18,
137 + TS_NEG_ELLIPSE_SC_INDEX : 0x19,
138 + TS_NEG_ELLIPSE_CB_INDEX : 0x1A,
139 + TS_NEG_INDEX_INDEX : 0x1B
140 +};
141 +
142 +var OrderEx = {
143 + ORDERFLAGS_EX_CACHE_BITMAP_REV3_SUPPORT : 0x0002,
144 + ORDERFLAGS_EX_ALTSEC_FRAME_MARKER_SUPPORT : 0x0004
145 +};
146 +
147 +/**
148 + * @see http://msdn.microsoft.com/en-us/library/cc240563.aspx
149 + */
150 +var InputFlags = {
151 + INPUT_FLAG_SCANCODES : 0x0001,
152 + INPUT_FLAG_MOUSEX : 0x0004,
153 + INPUT_FLAG_FASTPATH_INPUT : 0x0008,
154 + INPUT_FLAG_UNICODE : 0x0010,
155 + INPUT_FLAG_FASTPATH_INPUT2 : 0x0020,
156 + INPUT_FLAG_UNUSED1 : 0x0040,
157 + INPUT_FLAG_UNUSED2 : 0x0080,
158 + TS_INPUT_FLAG_MOUSE_HWHEEL : 0x0100
159 +};
160 +
161 +/**
162 + * @see http://msdn.microsoft.com/en-us/library/cc240564.aspx
163 + */
164 +var BrushSupport = {
165 + BRUSH_DEFAULT : 0x00000000,
166 + BRUSH_COLOR_8x8 : 0x00000001,
167 + BRUSH_COLOR_FULL : 0x00000002
168 +};
169 +
170 +/**
171 + * @see http://msdn.microsoft.com/en-us/library/cc240565.aspx
172 + */
173 +var GlyphSupport = {
174 + GLYPH_SUPPORT_NONE : 0x0000,
175 + GLYPH_SUPPORT_PARTIAL : 0x0001,
176 + GLYPH_SUPPORT_FULL : 0x0002,
177 + GLYPH_SUPPORT_ENCODE : 0x0003
178 +};
179 +
180 +/**
181 + * @see http://msdn.microsoft.com/en-us/library/cc240550.aspx
182 + */
183 +var OffscreenSupportLevel = {
184 + FALSE : 0x00000000,
185 + TRUE : 0x00000001
186 +};
187 +
188 +/**
189 + * @see http://msdn.microsoft.com/en-us/library/cc240551.aspx
190 + */
191 +var VirtualChannelCompressionFlag = {
192 + VCCAPS_NO_COMPR : 0x00000000,
193 + VCCAPS_COMPR_SC : 0x00000001,
194 + VCCAPS_COMPR_CS_8K : 0x00000002
195 +};
196 +
197 +/**
198 + * @see http://msdn.microsoft.com/en-us/library/cc240552.aspx
199 + */
200 +var SoundFlag = {
201 + NONE : 0x0000,
202 + SOUND_BEEPS_FLAG : 0x0001
203 +};
204 +
205 +/**
206 + * @see http://msdn.microsoft.com/en-us/library/cc240549.aspx
207 + * @param opt {object} type options
208 + * @returns {type.Component}
209 + */
210 +function generalCapability(opt) {
211 + var self = {
212 + __TYPE__ : CapsType.CAPSTYPE_GENERAL,
213 + osMajorType : new type.UInt16Le(),
214 + osMinorType : new type.UInt16Le(),
215 + protocolVersion : new type.UInt16Le(0x0200, {constant : true}),
216 + pad2octetsA : new type.UInt16Le(),
217 + generalCompressionTypes : new type.UInt16Le(0, {constant : true}),
218 + extraFlags : new type.UInt16Le(),
219 + updateCapabilityFlag : new type.UInt16Le(0, {constant : true}),
220 + remoteUnshareFlag : new type.UInt16Le(0, {constant : true}),
221 + generalCompressionLevel : new type.UInt16Le(0, {constant : true}),
222 + refreshRectSupport : new type.UInt8(),
223 + suppressOutputSupport : new type.UInt8()
224 + };
225 +
226 + return new type.Component(self, opt);
227 +}
228 +
229 +/**
230 + * @see http://msdn.microsoft.com/en-us/library/cc240554.aspx
231 + * @param opt {object} type options
232 + * @returns {type.Component}
233 + */
234 +function bitmapCapability(opt) {
235 + var self = {
236 + __TYPE__ : CapsType.CAPSTYPE_BITMAP,
237 + preferredBitsPerPixel : new type.UInt16Le(),
238 + receive1BitPerPixel : new type.UInt16Le(0x0001),
239 + receive4BitsPerPixel : new type.UInt16Le(0x0001),
240 + receive8BitsPerPixel : new type.UInt16Le(0x0001),
241 + desktopWidth : new type.UInt16Le(),
242 + desktopHeight : new type.UInt16Le(),
243 + pad2octets : new type.UInt16Le(),
244 + desktopResizeFlag : new type.UInt16Le(),
245 + bitmapCompressionFlag : new type.UInt16Le(0x0001, {constant : true}),
246 + highColorFlags : new type.UInt8(0),
247 + drawingFlags : new type.UInt8(),
248 + multipleRectangleSupport : new type.UInt16Le(0x0001, {constant : true}),
249 + pad2octetsB : new type.UInt16Le()
250 + };
251 +
252 + return new type.Component(self, opt);
253 +}
254 +
255 +/**
256 + * @see http://msdn.microsoft.com/en-us/library/cc240556.aspx
257 + * @param orders {type.BinaryString|null} list of available orders
258 + * @param opt {object} type options
259 + * @returns {type.Component}
260 + */
261 +function orderCapability(orders, opt) {
262 + if(orders && orders.size() !== 32) {
263 + throw new error.FatalError('NODE_RDP_PROTOCOL_PDU_CAPS_BAD_ORDERS_SIZE');
264 + }
265 +
266 + var self = {
267 + __TYPE__ : CapsType.CAPSTYPE_ORDER,
268 + terminalDescriptor : new type.BinaryString(Buffer.from(Array(16 + 1).join('\x00'), 'binary'), {readLength : new type.CallableValue(16)}),
269 + pad4octetsA : new type.UInt32Le(0),
270 + desktopSaveXGranularity : new type.UInt16Le(1),
271 + desktopSaveYGranularity : new type.UInt16Le(20),
272 + pad2octetsA : new type.UInt16Le(0),
273 + maximumOrderLevel : new type.UInt16Le(1),
274 + numberFonts : new type.UInt16Le(),
275 + orderFlags : new type.UInt16Le(OrderFlag.NEGOTIATEORDERSUPPORT),
276 + orderSupport : orders || new type.Factory(function(s) {
277 + self.orderSupport = new type.BinaryString(null, {readLength : new type.CallableValue(32)}).read(s);
278 + }),
279 + textFlags : new type.UInt16Le(),
280 + orderSupportExFlags : new type.UInt16Le(),
281 + pad4octetsB : new type.UInt32Le(),
282 + desktopSaveSize : new type.UInt32Le(480 * 480),
283 + pad2octetsC : new type.UInt16Le(),
284 + pad2octetsD : new type.UInt16Le(),
285 + textANSICodePage : new type.UInt16Le(0),
286 + pad2octetsE : new type.UInt16Le()
287 + };
288 +
289 + return new type.Component(self, opt);
290 +}
291 +
292 +/**
293 + * @see http://msdn.microsoft.com/en-us/library/cc240559.aspx
294 + * @param opt type options
295 + * @returns {type.Component}
296 + */
297 +function bitmapCacheCapability(opt) {
298 + var self = {
299 + __TYPE__ : CapsType.CAPSTYPE_BITMAPCACHE,
300 + pad1 : new type.UInt32Le(),
301 + pad2 : new type.UInt32Le(),
302 + pad3 : new type.UInt32Le(),
303 + pad4 : new type.UInt32Le(),
304 + pad5 : new type.UInt32Le(),
305 + pad6 : new type.UInt32Le(),
306 + cache0Entries : new type.UInt16Le(),
307 + cache0MaximumCellSize : new type.UInt16Le(),
308 + cache1Entries : new type.UInt16Le(),
309 + cache1MaximumCellSize : new type.UInt16Le(),
310 + cache2Entries : new type.UInt16Le(),
311 + cache2MaximumCellSize : new type.UInt16Le()
312 + };
313 +
314 + return new type.Component(self, opt);
315 +}
316 +
317 +/**
318 + *
319 + * @param isServer {boolean} true if in server mode
320 + * @param opt {object} type options
321 + * @returns {type.Component}
322 + */
323 +function pointerCapability(isServer, opt) {
324 + var self = {
325 + __TYPE__ : CapsType.CAPSTYPE_POINTER,
326 + colorPointerFlag : new type.UInt16Le(),
327 + colorPointerCacheSize : new type.UInt16Le(20),
328 + //old version of rdp doesn't support ...
329 + pointerCacheSize : new type.UInt16Le(null, {conditional : function() {
330 + return isServer || false;
331 + }})
332 + };
333 +
334 + return new type.Component(self, opt);
335 +}
336 +
337 +/**
338 + * @see http://msdn.microsoft.com/en-us/library/cc240563.aspx
339 + * @param opt {object} type options
340 + * @returns {type.Component}
341 + */
342 +function inputCapability(opt) {
343 + var self = {
344 + __TYPE__ : CapsType.CAPSTYPE_INPUT,
345 + inputFlags : new type.UInt16Le(),
346 + pad2octetsA : new type.UInt16Le(),
347 + // same value as gcc.ClientCoreSettings.kbdLayout
348 + keyboardLayout : new type.UInt32Le(),
349 + // same value as gcc.ClientCoreSettings.keyboardType
350 + keyboardType : new type.UInt32Le(),
351 + // same value as gcc.ClientCoreSettings.keyboardSubType
352 + keyboardSubType : new type.UInt32Le(),
353 + // same value as gcc.ClientCoreSettings.keyboardFnKeys
354 + keyboardFunctionKey : new type.UInt32Le(),
355 + // same value as gcc.ClientCoreSettingrrs.imeFileName
356 + imeFileName : new type.BinaryString(Buffer.from(Array(64 + 1).join('\x00'), 'binary'), {readLength : new type.CallableValue(64)})
357 + };
358 +
359 + return new type.Component(self, opt);
360 +}
361 +
362 +/**
363 + * @see http://msdn.microsoft.com/en-us/library/cc240564.aspx
364 + * @param opt {object} type options
365 + * @returns {type.Component}
366 + */
367 +function brushCapability(opt) {
368 + var self = {
369 + __TYPE__ : CapsType.CAPSTYPE_BRUSH,
370 + brushSupportLevel : new type.UInt32Le(BrushSupport.BRUSH_DEFAULT)
371 + };
372 +
373 + return new type.Component(self, opt);
374 +}
375 +
376 +/**
377 + * @see http://msdn.microsoft.com/en-us/library/cc240566.aspx
378 + * @param opt {object} type options
379 + * @returns {type.Component}
380 + */
381 +function cacheEntry(opt) {
382 + var self = {
383 + cacheEntries : new type.UInt16Le(),
384 + cacheMaximumCellSize : new type.UInt16Le()
385 + };
386 +
387 + return new type.Component(self, opt);
388 +}
389 +
390 +/**
391 + * @see http://msdn.microsoft.com/en-us/library/cc240565.aspx
392 + * @param entries {type.Component} cache entries
393 + * @param opt {object} type options
394 + * @returns {type.Component}
395 + */
396 +function glyphCapability(entries, opt) {
397 + var self = {
398 + __TYPE__ : CapsType.CAPSTYPE_GLYPHCACHE,
399 + glyphCache : entries || new type.Factory(function(s) {
400 + self.glyphCache = new type.Component([]);
401 + for(var i = 0; i < 10; i++) {
402 + self.glyphCache.obj.push(cacheEntry().read(s));
403 + }
404 + }),
405 + fragCache : new type.UInt32Le(),
406 + // all fonts are sent with bitmap format (very expensive)
407 + glyphSupportLevel : new type.UInt16Le(GlyphSupport.GLYPH_SUPPORT_NONE),
408 + pad2octets : new type.UInt16Le()
409 + };
410 +
411 + return new type.Component(self, opt);
412 +}
413 +
414 +/**
415 + * @see http://msdn.microsoft.com/en-us/library/cc240550.aspx
416 + * @param opt {object} type options
417 + * @returns {type.Component}
418 + */
419 +function offscreenBitmapCacheCapability(opt) {
420 + var self = {
421 + __TYPE__ : CapsType.CAPSTYPE_OFFSCREENCACHE,
422 + offscreenSupportLevel : new type.UInt32Le(OffscreenSupportLevel.FALSE),
423 + offscreenCacheSize : new type.UInt16Le(),
424 + offscreenCacheEntries : new type.UInt16Le()
425 + };
426 +
427 + return new type.Component(self, opt);
428 +}
429 +
430 +/**
431 + * @see http://msdn.microsoft.com/en-us/library/cc240551.aspx
432 + * @param opt {object} type options
433 + * @returns {type.Component}
434 + */
435 +function virtualChannelCapability(opt) {
436 + var self = {
437 + __TYPE__ : CapsType.CAPSTYPE_VIRTUALCHANNEL,
438 + flags : new type.UInt32Le(VirtualChannelCompressionFlag.VCCAPS_NO_COMPR),
439 + VCChunkSize : new type.UInt32Le(null, {optional : true})
440 + };
441 +
442 + return new type.Component(self, opt);
443 +}
444 +
445 +/**
446 + * @see http://msdn.microsoft.com/en-us/library/cc240552.aspx
447 + * @param opt {object} type options
448 + * @returns {type.Component}
449 + */
450 +function soundCapability(opt) {
451 + var self = {
452 + __TYPE__ : CapsType.CAPSTYPE_SOUND,
453 + soundFlags : new type.UInt16Le(SoundFlag.NONE),
454 + pad2octetsA : new type.UInt16Le()
455 + };
456 +
457 + return new type.Component(self, opt);
458 +}
459 +
460 +/**
461 + * @see http://msdn.microsoft.com/en-us/library/cc240568.aspx
462 + * @param opt {object} type options
463 + * @returns {type.Component}
464 + */
465 +function controlCapability(opt) {
466 + var self = {
467 + __TYPE__ : CapsType.CAPSTYPE_CONTROL,
468 + controlFlags : new type.UInt16Le(),
469 + remoteDetachFlag : new type.UInt16Le(),
470 + controlInterest : new type.UInt16Le(0x0002),
471 + detachInterest : new type.UInt16Le(0x0002)
472 + };
473 +
474 + return new type.Component(self, opt);
475 +}
476 +
477 +/**
478 + * @see http://msdn.microsoft.com/en-us/library/cc240569.aspx
479 + * @param opt {object} type options
480 + * @returns {type.Component}
481 + */
482 +function windowActivationCapability(opt) {
483 + var self = {
484 + __TYPE__ : CapsType.CAPSTYPE_ACTIVATION,
485 + helpKeyFlag : new type.UInt16Le(),
486 + helpKeyIndexFlag : new type.UInt16Le(),
487 + helpExtendedKeyFlag : new type.UInt16Le(),
488 + windowManagerKeyFlag : new type.UInt16Le()
489 + };
490 +
491 + return new type.Component(self, opt);
492 +}
493 +
494 +/**
495 + * @see http://msdn.microsoft.com/en-us/library/cc240571.aspx
496 + * @param opt {object} type options
497 + * @returns {type.Component}
498 + */
499 +function fontCapability(opt) {
500 + var self = {
501 + __TYPE__ : CapsType.CAPSTYPE_FONT,
502 + fontSupportFlags : new type.UInt16Le(0x0001),
503 + pad2octets : new type.UInt16Le()
504 + };
505 +
506 + return new type.Component(self, opt);
507 +}
508 +
509 +/**
510 + * @see http://msdn.microsoft.com/en-us/library/cc241564.aspx
511 + * @param opt {object} type options
512 + * @returns {type.Component}
513 + */
514 +function colorCacheCapability(opt) {
515 + var self = {
516 + __TYPE__ : CapsType.CAPSTYPE_COLORCACHE,
517 + colorTableCacheSize : new type.UInt16Le(0x0006),
518 + pad2octets : new type.UInt16Le()
519 + };
520 +
521 + return new type.Component(self, opt);
522 +}
523 +
524 +/**
525 + * @see http://msdn.microsoft.com/en-us/library/cc240570.aspx
526 + * @param opt {object} type options
527 + * @returns {type.Component}
528 + */
529 +function shareCapability(opt) {
530 + var self = {
531 + __TYPE__ : CapsType.CAPSTYPE_SHARE,
532 + nodeId : new type.UInt16Le(),
533 + pad2octets : new type.UInt16Le()
534 + };
535 +
536 + return new type.Component(self, opt);
537 +}
538 +
539 +/**
540 + * @see http://msdn.microsoft.com/en-us/library/cc240649.aspx
541 + * @param opt {object} type options
542 + * @returns {type.Component}
543 + */
544 +function multiFragmentUpdate(opt) {
545 + var self = {
546 + __TYPE__ : CapsType.CAPSETTYPE_MULTIFRAGMENTUPDATE,
547 + MaxRequestSize : new type.UInt32Le(0)
548 + };
549 +
550 + return new type.Component(self, opt);
551 +}
552 +
553 +/**
554 + * Capability wrapper packet
555 + * @see http://msdn.microsoft.com/en-us/library/cc240486.aspx
556 + * @param cap {type.Component}
557 + * @param opt {object} type options
558 + * @returns {type.Component}
559 + */
560 +function capability(cap, opt) {
561 + var self = {
562 + capabilitySetType : new type.UInt16Le(function() {
563 + return self.capability.obj.__TYPE__;
564 + }),
565 + lengthCapability : new type.UInt16Le(function() {
566 + return new type.Component(self).size();
567 + }),
568 + capability : cap || new type.Factory(function(s) {
569 + switch(self.capabilitySetType.value) {
570 + case CapsType.CAPSTYPE_GENERAL:
571 + self.capability = generalCapability({readLength : new type.CallableValue(function() {
572 + return self.lengthCapability.value - 4;
573 + })}).read(s);
574 + break;
575 + case CapsType.CAPSTYPE_BITMAP:
576 + self.capability = bitmapCapability({readLength : new type.CallableValue(function() {
577 + return self.lengthCapability.value - 4;
578 + })}).read(s);
579 + break;
580 + case CapsType.CAPSTYPE_ORDER:
581 + self.capability = orderCapability(null, {readLength : new type.CallableValue(function() {
582 + return self.lengthCapability.value - 4;
583 + })}).read(s);
584 + break;
585 + case CapsType.CAPSTYPE_BITMAPCACHE:
586 + self.capability = bitmapCacheCapability({readLength : new type.CallableValue(function() {
587 + return self.lengthCapability.value - 4;
588 + })}).read(s);
589 + break;
590 + case CapsType.CAPSTYPE_POINTER:
591 + self.capability = pointerCapability(false, {readLength : new type.CallableValue(function() {
592 + return self.lengthCapability.value - 4;
593 + })}).read(s);
594 + break;
595 + case CapsType.CAPSTYPE_INPUT:
596 + self.capability = inputCapability({readLength : new type.CallableValue(function() {
597 + return self.lengthCapability.value - 4;
598 + })}).read(s);
599 + break;
600 + case CapsType.CAPSTYPE_BRUSH:
601 + self.capability = brushCapability({readLength : new type.CallableValue(function() {
602 + return self.lengthCapability.value - 4;
603 + })}).read(s);
604 + break;
605 + case CapsType.CAPSTYPE_GLYPHCACHE:
606 + self.capability = glyphCapability(null, {readLength : new type.CallableValue(function() {
607 + return self.lengthCapability.value - 4;
608 + })}).read(s);
609 + break;
610 + case CapsType.CAPSTYPE_OFFSCREENCACHE:
611 + self.capability = offscreenBitmapCacheCapability({readLength : new type.CallableValue(function() {
612 + return self.lengthCapability.value - 4;
613 + })}).read(s);
614 + break;
615 + case CapsType.CAPSTYPE_VIRTUALCHANNEL:
616 + self.capability = virtualChannelCapability({readLength : new type.CallableValue(function() {
617 + return self.lengthCapability.value - 4;
618 + })}).read(s);
619 + break;
620 + case CapsType.CAPSTYPE_SOUND:
621 + self.capability = soundCapability({readLength : new type.CallableValue(function() {
622 + return self.lengthCapability.value - 4;
623 + })}).read(s);
624 + break;
625 + case CapsType.CAPSTYPE_CONTROL:
626 + self.capability = controlCapability({readLength : new type.CallableValue(function() {
627 + return self.lengthCapability.value - 4;
628 + })}).read(s);
629 + break;
630 + case CapsType.CAPSTYPE_ACTIVATION:
631 + self.capability = windowActivationCapability({readLength : new type.CallableValue(function() {
632 + return self.lengthCapability.value - 4;
633 + })}).read(s);
634 + break;
635 + case CapsType.CAPSTYPE_FONT:
636 + self.capability = fontCapability({readLength : new type.CallableValue(function() {
637 + return self.lengthCapability.value - 4;
638 + })}).read(s);
639 + break;
640 + case CapsType.CAPSTYPE_COLORCACHE:
641 + self.capability = colorCacheCapability({readLength : new type.CallableValue(function() {
642 + return self.lengthCapability.value - 4;
643 + })}).read(s);
644 + break;
645 + case CapsType.CAPSTYPE_SHARE:
646 + self.capability = shareCapability({readLength : new type.CallableValue(function() {
647 + return self.lengthCapability.value - 4;
648 + })}).read(s);
649 + break;
650 + case CapsType.CAPSETTYPE_MULTIFRAGMENTUPDATE:
651 + self.capability = multiFragmentUpdate({readLength : new type.CallableValue(function() {
652 + return self.lengthCapability.value - 4;
653 + })}).read(s);
654 + break;
655 + default:
656 + log.debug('unknown capability ' + self.capabilitySetType.value);
657 + self.capability = new type.BinaryString(null, {readLength : new type.CallableValue(function() {
658 + return self.lengthCapability.value - 4;
659 + })}).read(s);
660 + }
661 + })
662 + };
663 +
664 + return new type.Component(self, opt);
665 +}
666 +
667 +/**
668 + * Module exports
669 + */
670 +module.exports = {
671 + CapsType : CapsType,
672 + MajorType : MajorType,
673 + MinorType : MinorType,
674 + GeneralExtraFlag : GeneralExtraFlag,
675 + Boolean : Boolean,
676 + OrderFlag : OrderFlag,
677 + Order : Order,
678 + OrderEx : OrderEx,
679 + InputFlags : InputFlags,
680 + BrushSupport : BrushSupport,
681 + GlyphSupport : GlyphSupport,
682 + OffscreenSupportLevel : OffscreenSupportLevel,
683 + VirtualChannelCompressionFlag : VirtualChannelCompressionFlag,
684 + SoundFlag : SoundFlag,
685 + generalCapability : generalCapability,
686 + bitmapCapability : bitmapCapability,
687 + orderCapability : orderCapability,
688 + bitmapCacheCapability : bitmapCacheCapability,
689 + pointerCapability : pointerCapability,
690 + inputCapability : inputCapability,
691 + brushCapability : brushCapability,
692 + cacheEntry : cacheEntry,
693 + glyphCapability : glyphCapability,
694 + offscreenBitmapCacheCapability : offscreenBitmapCacheCapability,
695 + virtualChannelCapability : virtualChannelCapability,
696 + soundCapability : soundCapability,
697 + controlCapability : controlCapability,
698 + windowActivationCapability : windowActivationCapability,
699 + fontCapability : fontCapability,
700 + colorCacheCapability : colorCacheCapability,
701 + shareCapability : shareCapability,
702 + multiFragmentUpdate : multiFragmentUpdate,
703 + capability : capability
704 +};
\ No newline at end of file
rdp/protocol/pdu/data.js new
+1151
@@ -0,0 +1,1151 @@
1 +/*
2 + * Copyright (c) 2014-2015 Sylvain Peyrefitte
3 + *
4 + * This file is part of node-rdpjs.
5 + *
6 + * node-rdpjs is free software: you can redistribute it and/or modify
7 + * it under the terms of the GNU General Public License as published by
8 + * the Free Software Foundation, either version 3 of the License, or
9 + * (at your option) any later version.
10 + *
11 + * This program is distributed in the hope that it will be useful,
12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 + * GNU General Public License for more details.
15 + *
16 + * You should have received a copy of the GNU General Public License
17 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 + */
19 +
20 +var caps = require('./caps');
21 +var type = require('../../core').type;
22 +var log = require('../../core').log;
23 +
24 +/**
25 + * @see http://msdn.microsoft.com/en-us/library/cc240576.aspx
26 + */
27 +var PDUType = {
28 + PDUTYPE_DEMANDACTIVEPDU : 0x11,
29 + PDUTYPE_CONFIRMACTIVEPDU : 0x13,
30 + PDUTYPE_DEACTIVATEALLPDU : 0x16,
31 + PDUTYPE_DATAPDU : 0x17,
32 + PDUTYPE_SERVER_REDIR_PKT : 0x1A
33 +};
34 +
35 +/**
36 + * @see http://msdn.microsoft.com/en-us/library/cc240577.aspx
37 + */
38 +var PDUType2 = {
39 + PDUTYPE2_UPDATE : 0x02,
40 + PDUTYPE2_CONTROL : 0x14,
41 + PDUTYPE2_POINTER : 0x1B,
42 + PDUTYPE2_INPUT : 0x1C,
43 + PDUTYPE2_SYNCHRONIZE : 0x1F,
44 + PDUTYPE2_REFRESH_RECT : 0x21,
45 + PDUTYPE2_PLAY_SOUND : 0x22,
46 + PDUTYPE2_SUPPRESS_OUTPUT : 0x23,
47 + PDUTYPE2_SHUTDOWN_REQUEST : 0x24,
48 + PDUTYPE2_SHUTDOWN_DENIED : 0x25,
49 + PDUTYPE2_SAVE_SESSION_INFO : 0x26,
50 + PDUTYPE2_FONTLIST : 0x27,
51 + PDUTYPE2_FONTMAP : 0x28,
52 + PDUTYPE2_SET_KEYBOARD_INDICATORS : 0x29,
53 + PDUTYPE2_BITMAPCACHE_PERSISTENT_LIST : 0x2B,
54 + PDUTYPE2_BITMAPCACHE_ERROR_PDU : 0x2C,
55 + PDUTYPE2_SET_KEYBOARD_IME_STATUS : 0x2D,
56 + PDUTYPE2_OFFSCRCACHE_ERROR_PDU : 0x2E,
57 + PDUTYPE2_SET_ERROR_INFO_PDU : 0x2F,
58 + PDUTYPE2_DRAWNINEGRID_ERROR_PDU : 0x30,
59 + PDUTYPE2_DRAWGDIPLUS_ERROR_PDU : 0x31,
60 + PDUTYPE2_ARC_STATUS_PDU : 0x32,
61 + PDUTYPE2_STATUS_INFO_PDU : 0x36,
62 + PDUTYPE2_MONITOR_LAYOUT_PDU : 0x37
63 +};
64 +
65 +/**
66 + * @see http://msdn.microsoft.com/en-us/library/cc240577.aspx
67 + */
68 +var StreamId = {
69 + STREAM_UNDEFINED : 0x00,
70 + STREAM_LOW : 0x01,
71 + STREAM_MED : 0x02,
72 + STREAM_HI : 0x04
73 +};
74 +
75 +/**
76 + * @see http://msdn.microsoft.com/en-us/library/cc240577.aspx
77 + */
78 +var CompressionOrder = {
79 + CompressionTypeMask : 0x0F,
80 + PACKET_COMPRESSED : 0x20,
81 + PACKET_AT_FRONT : 0x40,
82 + PACKET_FLUSHED : 0x80
83 +};
84 +
85 +/**
86 + * @see http://msdn.microsoft.com/en-us/library/cc240577.aspx
87 + */
88 +var CompressionType = {
89 + PACKET_COMPR_TYPE_8K : 0x0,
90 + PACKET_COMPR_TYPE_64K : 0x1,
91 + PACKET_COMPR_TYPE_RDP6 : 0x2,
92 + PACKET_COMPR_TYPE_RDP61 : 0x3,
93 +};
94 +
95 +/**
96 + * @see http://msdn.microsoft.com/en-us/library/cc240492.aspx
97 + */
98 +var Action = {
99 + CTRLACTION_REQUEST_CONTROL : 0x0001,
100 + CTRLACTION_GRANTED_CONTROL : 0x0002,
101 + CTRLACTION_DETACH : 0x0003,
102 + CTRLACTION_COOPERATE : 0x0004
103 +};
104 +
105 +/**
106 + * @see http://msdn.microsoft.com/en-us/library/cc240495.aspx
107 + */
108 +var PersistentKeyListFlag = {
109 + PERSIST_FIRST_PDU : 0x01,
110 + PERSIST_LAST_PDU : 0x02
111 +};
112 +
113 +/**
114 + * @see http://msdn.microsoft.com/en-us/library/cc240612.aspx
115 + */
116 +var BitmapFlag = {
117 + BITMAP_COMPRESSION : 0x0001,
118 + NO_BITMAP_COMPRESSION_HDR : 0x0400
119 +};
120 +
121 +/**
122 + * @see http://msdn.microsoft.com/en-us/library/cc240608.aspx
123 + */
124 +var UpdateType = {
125 + UPDATETYPE_ORDERS : 0x0000,
126 + UPDATETYPE_BITMAP : 0x0001,
127 + UPDATETYPE_PALETTE : 0x0002,
128 + UPDATETYPE_SYNCHRONIZE : 0x0003
129 +};
130 +
131 +/**
132 + * @see http://msdn.microsoft.com/en-us/library/cc240608.aspx
133 + */
134 +var UpdateType = {
135 + UPDATETYPE_ORDERS : 0x0000,
136 + UPDATETYPE_BITMAP : 0x0001,
137 + UPDATETYPE_PALETTE : 0x0002,
138 + UPDATETYPE_SYNCHRONIZE : 0x0003
139 +};
140 +
141 +/**
142 + * @see http://msdn.microsoft.com/en-us/library/cc240583.aspx
143 + */
144 +var InputMessageType = {
145 + INPUT_EVENT_SYNC : 0x0000,
146 + INPUT_EVENT_UNUSED : 0x0002,
147 + INPUT_EVENT_SCANCODE : 0x0004,
148 + INPUT_EVENT_UNICODE : 0x0005,
149 + INPUT_EVENT_MOUSE : 0x8001,
150 + INPUT_EVENT_MOUSEX : 0x8002
151 +};
152 +
153 +/**
154 + * @see http://msdn.microsoft.com/en-us/library/cc240586.aspx
155 + */
156 +var PointerFlag = {
157 + PTRFLAGS_HWHEEL : 0x0400,
158 + PTRFLAGS_WHEEL : 0x0200,
159 + PTRFLAGS_WHEEL_NEGATIVE : 0x0100,
160 + WheelRotationMask : 0x01FF,
161 + PTRFLAGS_MOVE : 0x0800,
162 + PTRFLAGS_DOWN : 0x8000,
163 + PTRFLAGS_BUTTON1 : 0x1000,
164 + PTRFLAGS_BUTTON2 : 0x2000,
165 + PTRFLAGS_BUTTON3 : 0x4000
166 +};
167 +
168 +/**
169 + * @see http://msdn.microsoft.com/en-us/library/cc240584.aspx
170 + */
171 +var KeyboardFlag = {
172 + KBDFLAGS_EXTENDED : 0x0100,
173 + KBDFLAGS_DOWN : 0x4000,
174 + KBDFLAGS_RELEASE : 0x8000
175 +};
176 +
177 +/**
178 + * @see http://msdn.microsoft.com/en-us/library/cc240622.aspx
179 + */
180 +var FastPathUpdateType = {
181 + FASTPATH_UPDATETYPE_ORDERS : 0x0,
182 + FASTPATH_UPDATETYPE_BITMAP : 0x1,
183 + FASTPATH_UPDATETYPE_PALETTE : 0x2,
184 + FASTPATH_UPDATETYPE_SYNCHRONIZE : 0x3,
185 + FASTPATH_UPDATETYPE_SURFCMDS : 0x4,
186 + FASTPATH_UPDATETYPE_PTR_NULL : 0x5,
187 + FASTPATH_UPDATETYPE_PTR_DEFAULT : 0x6,
188 + FASTPATH_UPDATETYPE_PTR_POSITION : 0x8,
189 + FASTPATH_UPDATETYPE_COLOR : 0x9,
190 + FASTPATH_UPDATETYPE_CACHED : 0xA,
191 + FASTPATH_UPDATETYPE_POINTER : 0xB
192 +};
193 +
194 +/**
195 + * @see http://msdn.microsoft.com/en-us/library/cc240622.aspx
196 + */
197 +var FastPathOutputCompression = {
198 + FASTPATH_OUTPUT_COMPRESSION_USED : 0x2
199 +};
200 +
201 +/**
202 + * @see http://msdn.microsoft.com/en-us/library/cc240648.aspx
203 + */
204 +var Display = {
205 + SUPPRESS_DISPLAY_UPDATES : 0x00,
206 + ALLOW_DISPLAY_UPDATES : 0x01
207 +};
208 +
209 +/**
210 + * @see https://msdn.microsoft.com/en-us/library/cc240588.aspx
211 + */
212 +var ToogleFlag = {
213 + TS_SYNC_SCROLL_LOCK : 0x00000001,
214 + TS_SYNC_NUM_LOCK : 0x00000002,
215 + TS_SYNC_CAPS_LOCK : 0x00000004,
216 + TS_SYNC_KANA_LOCK : 0x00000008
217 +};
218 +
219 +/**
220 + * @see http://msdn.microsoft.com/en-us/library/cc240544.aspx
221 + */
222 +var ErrorInfo = {
223 + ERRINFO_RPC_INITIATED_DISCONNECT : 0x00000001,
224 + ERRINFO_RPC_INITIATED_LOGOFF : 0x00000002,
225 + ERRINFO_IDLE_TIMEOUT : 0x00000003,
226 + ERRINFO_LOGON_TIMEOUT : 0x00000004,
227 + ERRINFO_DISCONNECTED_BY_OTHERCONNECTION : 0x00000005,
228 + ERRINFO_OUT_OF_MEMORY : 0x00000006,
229 + ERRINFO_SERVER_DENIED_CONNECTION : 0x00000007,
230 + ERRINFO_SERVER_INSUFFICIENT_PRIVILEGES : 0x00000009,
231 + ERRINFO_SERVER_FRESH_CREDENTIALS_REQUIRED : 0x0000000A,
232 + ERRINFO_RPC_INITIATED_DISCONNECT_BYUSER : 0x0000000B,
233 + ERRINFO_LOGOFF_BY_USER : 0x0000000C,
234 + ERRINFO_LICENSE_INTERNAL : 0x00000100,
235 + ERRINFO_LICENSE_NO_LICENSE_SERVER : 0x00000101,
236 + ERRINFO_LICENSE_NO_LICENSE : 0x00000102,
237 + ERRINFO_LICENSE_BAD_CLIENT_MSG : 0x00000103,
238 + ERRINFO_LICENSE_HWID_DOESNT_MATCH_LICENSE : 0x00000104,
239 + ERRINFO_LICENSE_BAD_CLIENT_LICENSE : 0x00000105,
240 + ERRINFO_LICENSE_CANT_FINISH_PROTOCOL : 0x00000106,
241 + ERRINFO_LICENSE_CLIENT_ENDED_PROTOCOL : 0x00000107,
242 + ERRINFO_LICENSE_BAD_CLIENT_ENCRYPTION : 0x00000108,
243 + ERRINFO_LICENSE_CANT_UPGRADE_LICENSE : 0x00000109,
244 + ERRINFO_LICENSE_NO_REMOTE_CONNECTIONS : 0x0000010A,
245 + ERRINFO_CB_DESTINATION_NOT_FOUND : 0x0000400,
246 + ERRINFO_CB_LOADING_DESTINATION : 0x0000402,
247 + ERRINFO_CB_REDIRECTING_TO_DESTINATION : 0x0000404,
248 + ERRINFO_CB_SESSION_ONLINE_VM_WAKE : 0x0000405,
249 + ERRINFO_CB_SESSION_ONLINE_VM_BOOT : 0x0000406,
250 + ERRINFO_CB_SESSION_ONLINE_VM_NO_DNS : 0x0000407,
251 + ERRINFO_CB_DESTINATION_POOL_NOT_FREE : 0x0000408,
252 + ERRINFO_CB_CONNECTION_CANCELLED : 0x0000409,
253 + ERRINFO_CB_CONNECTION_ERROR_INVALID_SETTINGS : 0x0000410,
254 + ERRINFO_CB_SESSION_ONLINE_VM_BOOT_TIMEOUT : 0x0000411,
255 + ERRINFO_CB_SESSION_ONLINE_VM_SESSMON_FAILED : 0x0000412,
256 + ERRINFO_UNKNOWNPDUTYPE2 : 0x000010C9,
257 + ERRINFO_UNKNOWNPDUTYPE : 0x000010CA,
258 + ERRINFO_DATAPDUSEQUENCE : 0x000010CB,
259 + ERRINFO_CONTROLPDUSEQUENCE : 0x000010CD,
260 + ERRINFO_INVALIDCONTROLPDUACTION : 0x000010CE,
261 + ERRINFO_INVALIDINPUTPDUTYPE : 0x000010CF,
262 + ERRINFO_INVALIDINPUTPDUMOUSE : 0x000010D0,
263 + ERRINFO_INVALIDREFRESHRECTPDU : 0x000010D1,
264 + ERRINFO_CREATEUSERDATAFAILED : 0x000010D2,
265 + ERRINFO_CONNECTFAILED : 0x000010D3,
266 + ERRINFO_CONFIRMACTIVEWRONGSHAREID : 0x000010D4,
267 + ERRINFO_CONFIRMACTIVEWRONGORIGINATOR : 0x000010D5,
268 + ERRINFO_PERSISTENTKEYPDUBADLENGTH : 0x000010DA,
269 + ERRINFO_PERSISTENTKEYPDUILLEGALFIRST : 0x000010DB,
270 + ERRINFO_PERSISTENTKEYPDUTOOMANYTOTALKEYS : 0x000010DC,
271 + ERRINFO_PERSISTENTKEYPDUTOOMANYCACHEKEYS : 0x000010DD,
272 + ERRINFO_INPUTPDUBADLENGTH : 0x000010DE,
273 + ERRINFO_BITMAPCACHEERRORPDUBADLENGTH : 0x000010DF,
274 + ERRINFO_SECURITYDATATOOSHORT : 0x000010E0,
275 + ERRINFO_VCHANNELDATATOOSHORT : 0x000010E1,
276 + ERRINFO_SHAREDATATOOSHORT : 0x000010E2,
277 + ERRINFO_BADSUPRESSOUTPUTPDU : 0x000010E3,
278 + ERRINFO_CONFIRMACTIVEPDUTOOSHORT : 0x000010E5,
279 + ERRINFO_CAPABILITYSETTOOSMALL : 0x000010E7,
280 + ERRINFO_CAPABILITYSETTOOLARGE : 0x000010E8,
281 + ERRINFO_NOCURSORCACHE : 0x000010E9,
282 + ERRINFO_BADCAPABILITIES : 0x000010EA,
283 + ERRINFO_VIRTUALCHANNELDECOMPRESSIONERR : 0x000010EC,
284 + ERRINFO_INVALIDVCCOMPRESSIONTYPE : 0x000010ED,
285 + ERRINFO_INVALIDCHANNELID : 0x000010EF,
286 + ERRINFO_VCHANNELSTOOMANY : 0x000010F0,
287 + ERRINFO_REMOTEAPPSNOTENABLED : 0x000010F3,
288 + ERRINFO_CACHECAPNOTSET : 0x000010F4,
289 + ERRINFO_BITMAPCACHEERRORPDUBADLENGTH2 : 0x000010F5,
290 + ERRINFO_OFFSCRCACHEERRORPDUBADLENGTH : 0x000010F6,
291 + ERRINFO_DNGCACHEERRORPDUBADLENGTH : 0x000010F7,
292 + ERRINFO_GDIPLUSPDUBADLENGTH : 0x000010F8,
293 + ERRINFO_SECURITYDATATOOSHORT2 : 0x00001111,
294 + ERRINFO_SECURITYDATATOOSHORT3 : 0x00001112,
295 + ERRINFO_SECURITYDATATOOSHORT4 : 0x00001113,
296 + ERRINFO_SECURITYDATATOOSHORT5 : 0x00001114,
297 + ERRINFO_SECURITYDATATOOSHORT6 : 0x00001115,
298 + ERRINFO_SECURITYDATATOOSHORT7 : 0x00001116,
299 + ERRINFO_SECURITYDATATOOSHORT8 : 0x00001117,
300 + ERRINFO_SECURITYDATATOOSHORT9 : 0x00001118,
301 + ERRINFO_SECURITYDATATOOSHORT10 : 0x00001119,
302 + ERRINFO_SECURITYDATATOOSHORT11 : 0x0000111A,
303 + ERRINFO_SECURITYDATATOOSHORT12 : 0x0000111B,
304 + ERRINFO_SECURITYDATATOOSHORT13 : 0x0000111C,
305 + ERRINFO_SECURITYDATATOOSHORT14 : 0x0000111D,
306 + ERRINFO_SECURITYDATATOOSHORT15 : 0x0000111E,
307 + ERRINFO_SECURITYDATATOOSHORT16 : 0x0000111F,
308 + ERRINFO_SECURITYDATATOOSHORT17 : 0x00001120,
309 + ERRINFO_SECURITYDATATOOSHORT18 : 0x00001121,
310 + ERRINFO_SECURITYDATATOOSHORT19 : 0x00001122,
311 + ERRINFO_SECURITYDATATOOSHORT20 : 0x00001123,
312 + ERRINFO_SECURITYDATATOOSHORT21 : 0x00001124,
313 + ERRINFO_SECURITYDATATOOSHORT22 : 0x00001125,
314 + ERRINFO_SECURITYDATATOOSHORT23 : 0x00001126,
315 + ERRINFO_BADMONITORDATA : 0x00001129,
316 + ERRINFO_VCDECOMPRESSEDREASSEMBLEFAILED : 0x0000112A,
317 + ERRINFO_VCDATATOOLONG : 0x0000112B,
318 + ERRINFO_BAD_FRAME_ACK_DATA : 0x0000112C,
319 + ERRINFO_GRAPHICSMODENOTSUPPORTED : 0x0000112D,
320 + ERRINFO_GRAPHICSSUBSYSTEMRESETFAILED : 0x0000112E,
321 + ERRINFO_GRAPHICSSUBSYSTEMFAILED : 0x0000112F,
322 + ERRINFO_TIMEZONEKEYNAMELENGTHTOOSHORT : 0x00001130,
323 + ERRINFO_TIMEZONEKEYNAMELENGTHTOOLONG : 0x00001131,
324 + ERRINFO_DYNAMICDSTDISABLEDFIELDMISSING : 0x00001132,
325 + ERRINFO_VCDECODINGERROR : 0x00001133,
326 + ERRINFO_UPDATESESSIONKEYFAILED : 0x00001191,
327 + ERRINFO_DECRYPTFAILED : 0x00001192,
328 + ERRINFO_ENCRYPTFAILED : 0x00001193,
329 + ERRINFO_ENCPKGMISMATCH : 0x00001194,
330 + ERRINFO_DECRYPTFAILED2 : 0x00001195
331 +};
332 +
333 +/**
334 + * @see http://msdn.microsoft.com/en-us/library/cc240576.aspx
335 + * @param length {integer} length of entire pdu packet
336 + * @param pduType {PDUType.*} type of pdu packet
337 + * @param userId {integer}
338 + * @param opt {object} type option
339 + * @returns {type.Component}
340 + */
341 +function shareControlHeader(length, pduType, userId, opt) {
342 + var self = {
343 + totalLength : new type.UInt16Le(length),
344 + pduType : new type.UInt16Le(pduType),
345 + // for xp sp3 and deactiveallpdu PDUSource may not be present
346 + PDUSource : new type.UInt16Le(userId, { optional : true })
347 + };
348 +
349 + return new type.Component(self, opt);
350 +}
351 +
352 +/**
353 + * @see http://msdn.microsoft.com/en-us/library/cc240577.aspx
354 + * @param length {integer} lezngth of entire packet
355 + * @param pduType2 {PDUType2.*} sub PDU type
356 + * @param shareId {integer} global layer id
357 + * @param opt {object} type option
358 + * @returns {type.Component}
359 + */
360 +function shareDataHeader(length, pduType2, shareId, opt) {
361 + var self = {
362 + shareId : new type.UInt32Le(shareId),
363 + pad1 : new type.UInt8(),
364 + streamId : new type.UInt8(StreamId.STREAM_LOW),
365 + uncompressedLength : new type.UInt16Le(function() {
366 + return length.value - 8;
367 + }),
368 + pduType2 : new type.UInt8(pduType2),
369 + compressedType : new type.UInt8(),
370 + compressedLength : new type.UInt16Le()
371 + };
372 +
373 + return new type.Component(self, opt);
374 +}
375 +
376 +/**
377 + * @see http://msdn.microsoft.com/en-us/library/cc240485.aspx
378 + * @param capabilities {type.Component} capabilities array
379 + * @param opt {object} type option
380 + * @returns {type.Component}
381 + */
382 +function demandActivePDU(capabilities, opt) {
383 + var self = {
384 + __PDUTYPE__ : PDUType.PDUTYPE_DEMANDACTIVEPDU,
385 + shareId : new type.UInt32Le(),
386 + lengthSourceDescriptor : new type.UInt16Le(function() {
387 + return self.sourceDescriptor.size();
388 + }),
389 + lengthCombinedCapabilities : new type.UInt16Le(function() {
390 + return self.numberCapabilities.size() + self.pad2Octets.size() + self.capabilitySets.size();
391 + }),
392 + sourceDescriptor : new type.BinaryString(Buffer.from('node-rdpjs', 'binary'), { readLength : new type.CallableValue(function() {
393 + return self.lengthSourceDescriptor.value
394 + }) }),
395 + numberCapabilities : new type.UInt16Le(function() {
396 + return self.capabilitySets.obj.length;
397 + }),
398 + pad2Octets : new type.UInt16Le(),
399 + capabilitySets : capabilities || new type.Factory(function(s) {
400 + self.capabilitySets = new type.Component([]);
401 + for(var i = 0; i < self.numberCapabilities.value; i++) {
402 + self.capabilitySets.obj.push(caps.capability().read(s))
403 + }
404 + }),
405 + sessionId : new type.UInt32Le()
406 + };
407 +
408 + return new type.Component(self, opt);
409 +}
410 +
411 +/**
412 + * @see http://msdn.microsoft.com/en-us/library/cc240488.aspx
413 + * @param capabilities {type.Component} capabilities array
414 + * @param shareId {integer} session id
415 + * @param opt {object} type option
416 + * @returns {type.Component}
417 + */
418 +function confirmActivePDU(capabilities, shareId, opt) {
419 + var self = {
420 + __PDUTYPE__ : PDUType.PDUTYPE_CONFIRMACTIVEPDU,
421 + shareId : new type.UInt32Le(shareId),
422 + originatorId : new type.UInt16Le(0x03EA, { constant : true }),
423 + lengthSourceDescriptor : new type.UInt16Le(function() {
424 + return self.sourceDescriptor.size();
425 + }),
426 + lengthCombinedCapabilities : new type.UInt16Le(function() {
427 + return self.numberCapabilities.size() + self.pad2Octets.size() + self.capabilitySets.size();
428 + }),
429 + sourceDescriptor : new type.BinaryString(Buffer.from('rdpy', 'binary'), { readLength : new type.CallableValue(function() {
430 + return self.lengthSourceDescriptor.value
431 + }) }),
432 + numberCapabilities : new type.UInt16Le(function() {
433 + return self.capabilitySets.obj.length;
434 + }),
435 + pad2Octets : new type.UInt16Le(),
436 + capabilitySets : capabilities || new type.Factory(function(s) {
437 + self.capabilitySets = new type.Component([]);
438 + for(var i = 0; i < self.numberCapabilities.value; i++) {
439 + self.capabilitySets.obj.push(caps.capability().read(s))
440 + }
441 + })
442 + };
443 +
444 + return new type.Component(self, opt);
445 +}
446 +
447 +/**
448 + * @see http://msdn.microsoft.com/en-us/library/cc240536.aspx
449 + * @param opt {object} type option
450 + * @returns {type.Component}
451 + */
452 +function deactiveAllPDU(opt) {
453 + var self = {
454 + __PDUTYPE__ : PDUType.PDUTYPE_DEACTIVATEALLPDU,
455 + shareId : new type.UInt32Le(),
456 + lengthSourceDescriptor : new type.UInt16Le(function() {
457 + return self.sourceDescriptor.size();
458 + }),
459 + sourceDescriptor : new type.BinaryString(Buffer.from('rdpy', 'binary'), { readLength : new type.CallableValue(function() {
460 + self.lengthSourceDescriptor
461 + }) })
462 + };
463 +
464 + return new type.Component(self, opt);
465 +}
466 +
467 +/**
468 + * @see http://msdn.microsoft.com/en-us/library/cc240490.aspx
469 + * @param opt {object} type option
470 + * @returns {type.Component}
471 + */
472 +function synchronizeDataPDU(targetUser, opt) {
473 + var self = {
474 + __PDUTYPE2__ : PDUType2.PDUTYPE2_SYNCHRONIZE,
475 + messageType : new type.UInt16Le(1, { constant : true }),
476 + targetUser : new type.UInt16Le(targetUser)
477 + };
478 +
479 + return new type.Component(self, opt);
480 +}
481 +
482 +/**
483 + * @see http://msdn.microsoft.com/en-us/library/cc240492.aspx
484 + * @param action {integer}
485 + * @param opt {object} type option
486 + * @returns {type.Component}
487 + */
488 +function controlDataPDU(action, opt) {
489 + var self = {
490 + __PDUTYPE2__ : PDUType2.PDUTYPE2_CONTROL,
491 + action : new type.UInt16Le(action),
492 + grantId : new type.UInt16Le(),
493 + controlId : new type.UInt32Le()
494 + };
495 +
496 + return new type.Component(self, opt);
497 +}
498 +
499 +/**
500 + * @see http://msdn.microsoft.com/en-us/library/cc240544.aspx
501 + * @param errorInfo {integer}
502 + * @param opt {object} type option
503 + * @returns {type.Component}
504 + */
505 +function errorInfoDataPDU(errorInfo, opt) {
506 + var self = {
507 + __PDUTYPE2__ : PDUType2.PDUTYPE2_SET_ERROR_INFO_PDU,
508 + errorInfo : new type.UInt32Le(errorInfo)
509 + };
510 +
511 + return new type.Component(self, opt);
512 +}
513 +
514 +/**
515 + * @see http://msdn.microsoft.com/en-us/library/cc240498.aspx
516 + * @param opt {object} type option
517 + * @returns {type.Component}
518 + */
519 +function fontListDataPDU(opt) {
520 + var self = {
521 + __PDUTYPE2__ : PDUType2.PDUTYPE2_FONTLIST,
522 + numberFonts : new type.UInt16Le(),
523 + totalNumFonts : new type.UInt16Le(),
524 + listFlags : new type.UInt16Le(0x0003),
525 + entrySize : new type.UInt16Le(0x0032)
526 + };
527 +
528 + return new type.Component(self, opt);
529 +}
530 +
531 +/**
532 + * @see http://msdn.microsoft.com/en-us/library/cc240498.aspx
533 + * @param opt {object} type option
534 + * @returns {type.Component}
535 + */
536 +function fontMapDataPDU(opt) {
537 + var self = {
538 + __PDUTYPE2__ : PDUType2.PDUTYPE2_FONTMAP,
539 + numberEntries : new type.UInt16Le(),
540 + totalNumEntries : new type.UInt16Le(),
541 + mapFlags : new type.UInt16Le(0x0003),
542 + entrySize : new type.UInt16Le(0x0004)
543 + };
544 +
545 + return new type.Component(self, opt);
546 +}
547 +
548 +/**
549 + * @see http://msdn.microsoft.com/en-us/library/cc240496.aspx
550 + * @param opt {object} type option
551 + * @returns {type.Component}
552 + */
553 +function persistentListEntry(opt) {
554 + var self = {
555 + key1 : new type.UInt32Le(),
556 + key2 : new type.UInt32Le()
557 + };
558 +
559 + return new type.Component(self, opt);
560 +}
561 +
562 +/**
563 + * @see http://msdn.microsoft.com/en-us/library/cc240495.aspx
564 + * @param entries {type.Component}
565 + * @param opt {object} type option
566 + * @returns {type.Component}
567 + */
568 +function persistentListPDU(entries, opt) {
569 + var self = {
570 + __PDUTYPE2__ : PDUType2.PDUTYPE2_BITMAPCACHE_PERSISTENT_LIST,
571 + numEntriesCache0 : new type.UInt16Le(),
572 + numEntriesCache1 : new type.UInt16Le(),
573 + numEntriesCache2 : new type.UInt16Le(),
574 + numEntriesCache3 : new type.UInt16Le(),
575 + numEntriesCache4 : new type.UInt16Le(),
576 + totalEntriesCache0 : new type.UInt16Le(),
577 + totalEntriesCache1 : new type.UInt16Le(),
578 + totalEntriesCache2 : new type.UInt16Le(),
579 + totalEntriesCache3 : new type.UInt16Le(),
580 + totalEntriesCache4 : new type.UInt16Le(),
581 + bitMask : new type.UInt8(),
582 + pad2 : new type.UInt8(),
583 + pad3 : new type.UInt16Le(),
584 + entries : entries || new type.Factory(function(s) {
585 + var numEntries = self.numEntriesCache0.value + self.numEntriesCache1.value + self.numEntriesCache2.value + self.numEntriesCache3.value + self.numEntriesCache4.value;
586 + self.entries = new type.Component([]);
587 + for(var i = 0; i < numEntries; i++) {
588 + self.entries.obj.push(persistentListEntry().read(s));
589 + }
590 + })
591 + };
592 +
593 + return new type.Component(self, opt);
594 +}
595 +
596 +/**
597 + * @see https://msdn.microsoft.com/en-us/library/cc240588.aspx
598 + * @param opt {object} type option
599 + * @returns {type.Component}
600 + */
601 +function synchronizeEvent(opt) {
602 + var self = {
603 + __INPUT_MESSAGE_TYPE__ : InputMessageType.INPUT_EVENT_SYNC,
604 + pad2Octets : new type.UInt16Le(),
605 + toggleFlags : new type.UInt32Le()
606 + };
607 +
608 + return new type.Component(self, opt);
609 +}
610 +
611 +/**
612 + * @see http://msdn.microsoft.com/en-us/library/cc240586.aspx
613 + * @param opt {object} type option
614 + * @returns {type.Component}
615 + */
616 +function pointerEvent(opt) {
617 + var self = {
618 + __INPUT_MESSAGE_TYPE__ : InputMessageType.INPUT_EVENT_MOUSE,
619 + pointerFlags : new type.UInt16Le(),
620 + xPos : new type.UInt16Le(),
621 + yPos : new type.UInt16Le()
622 + };
623 +
624 + return new type.Component(self, opt);
625 +}
626 +
627 +/**
628 + * @see http://msdn.microsoft.com/en-us/library/cc240584.aspx
629 + * @param opt {object} type option
630 + * @returns {type.Component}
631 + */
632 +function scancodeKeyEvent(opt) {
633 + var self = {
634 + __INPUT_MESSAGE_TYPE__ : InputMessageType.INPUT_EVENT_SCANCODE,
635 + keyboardFlags : new type.UInt16Le(),
636 + keyCode : new type.UInt16Le(),
637 + pad2Octets : new type.UInt16Le()
638 + };
639 +
640 + return new type.Component(self, opt);
641 +}
642 +
643 +/**
644 + * @see http://msdn.microsoft.com/en-us/library/cc240585.aspx
645 + * @param opt {object} type option
646 + * @returns {type.Component}
647 + */
648 +function unicodeKeyEvent(opt) {
649 + var self = {
650 + __INPUT_MESSAGE_TYPE__ : InputMessageType.INPUT_EVENT_UNICODE,
651 + keyboardFlags : new type.UInt16Le(),
652 + unicode : new type.UInt16Le(),
653 + pad2Octets : new type.UInt16Le()
654 + };
655 +
656 + return new type.Component(self, opt);
657 +}
658 +
659 +/**
660 + * @see http://msdn.microsoft.com/en-us/library/cc240583.aspx
661 + * @param slowPathInputData {type.Component} message generate for slow path input event
662 + * @param opt {object} type option
663 + * @returns {type.Component}
664 + */
665 +function slowPathInputEvent(slowPathInputData, opt) {
666 + var self = {
667 + eventTime : new type.UInt32Le(),
668 + messageType : new type.UInt16Le(function() {
669 + return self.slowPathInputData.obj.__INPUT_MESSAGE_TYPE__;
670 + }),
671 + slowPathInputData : slowPathInputData || new type.Factory(function(s) {
672 + switch(self.messageType.value) {
673 + case InputMessageType.INPUT_EVENT_SYNC:
674 + self.slowPathInputData = synchronizeEvent().read(s);
675 + break;
676 + case InputMessageType.INPUT_EVENT_MOUSE:
677 + self.slowPathInputData = pointerEvent().read(s);
678 + break;
679 + case InputMessageType.INPUT_EVENT_SCANCODE:
680 + self.slowPathInputData = scancodeKeyEvent().read(s);
681 + break;
682 + case InputMessageType.INPUT_EVENT_UNICODE:
683 + self.slowPathInputData = unicodeKeyEvent().read(s);
684 + break;
685 + default:
686 + log.error('unknown slowPathInputEvent ' + self.messageType.value);
687 + }
688 + })
689 + };
690 +
691 + return new type.Component(self, opt);
692 +}
693 +
694 +/**
695 + * @see http://msdn.microsoft.com/en-us/library/cc746160.aspx
696 + * @param inputs {type.Component} list of inputs
697 + * @param opt {object} type option
698 + * @returns {type.Component}
699 + */
700 +function clientInputEventPDU(inputs, opt) {
701 + var self = {
702 + __PDUTYPE2__ : PDUType2.PDUTYPE2_INPUT,
703 + numEvents : new type.UInt16Le(function() {
704 + return self.slowPathInputEvents.obj.length;
705 + }),
706 + pad2Octets : new type.UInt16Le(),
707 + slowPathInputEvents : inputs || new type.Factory(function(s) {
708 + self.slowPathInputEvents = new type.Component([]);
709 + for(var i = 0; i < self.numEvents.value; i++) {
710 + self.slowPathInputEvents.obj.push(slowPathInputEvent().read(s));
711 + }
712 + })
713 + };
714 +
715 + return new type.Component(self, opt);
716 +}
717 +
718 +/**
719 + * @param opt {object} type option
720 + * @returns {type.Component}
721 + */
722 +function shutdownRequestPDU(opt) {
723 + var self = {
724 + __PDUTYPE2__ : PDUType2.PDUTYPE2_SHUTDOWN_REQUEST
725 + };
726 +
727 + return new type.Component(self, opt);
728 +}
729 +
730 +/**
731 + * @param opt {object} type option
732 + * @returns {type.Component}
733 + */
734 +function shutdownDeniedPDU(opt) {
735 + var self = {
736 + __PDUTYPE2__ : PDUType2.PDUTYPE2_SHUTDOWN_DENIED
737 + };
738 +
739 + return new type.Component(self, opt);
740 +}
741 +
742 +/**
743 + * @see http://msdn.microsoft.com/en-us/library/cc240643.aspx
744 + * @param opt {object} type option
745 + * @returns {type.Component}
746 + */
747 +function inclusiveRectangle(opt) {
748 + var self = {
749 + left : new type.UInt16Le(),
750 + top : new type.UInt16Le(),
751 + right : new type.UInt16Le(),
752 + bottom : new type.UInt16Le()
753 + };
754 +
755 + return new type.Component(self, opt);
756 +}
757 +
758 +/**
759 + * @see http://msdn.microsoft.com/en-us/library/cc240648.aspx
760 + * @param opt {object} type option
761 + * @returns {type.Component}
762 + */
763 +function supressOutputDataPDU(opt) {
764 + var self = {
765 + __PDUTYPE2__ : PDUType2.PDUTYPE2_SUPPRESS_OUTPUT,
766 + allowDisplayUpdates : new type.UInt8(),
767 + pad3Octets : new type.Component([new type.UInt8(), new type.UInt8(), new type.UInt8()]),
768 + desktopRect : inclusiveRectangle({ conditional : function() {
769 + return self.allowDisplayUpdates.value === Display.ALLOW_DISPLAY_UPDATES;
770 + } })
771 + };
772 +
773 + return new type.Component(self, opt);
774 +}
775 +
776 +/**
777 + * @see http://msdn.microsoft.com/en-us/library/cc240646.aspx
778 + * @param rectangles {type.Component} list of inclusive rectangles
779 + * @param opt {object} type option
780 + * @returns {type.Component}
781 + */
782 +function refreshRectPDU(rectangles, opt) {
783 + var self = {
784 + __PDUTYPE2__ : PDUType2.PDUTYPE2_REFRESH_RECT,
785 + numberOfAreas : UInt8(function() {
786 + return self.areasToRefresh.obj.length;
787 + }),
788 + pad3Octets : new type.Component([new type.UInt8(), new type.UInt8(), new type.UInt8()]),
789 + areasToRefresh : rectangles || new type.Factory(function(s) {
790 + self.areasToRefresh = new type.Component([]);
791 + for(var i = 0; i < self.numberOfAreas.value; i++) {
792 + self.areasToRefresh.obj.push(inclusiveRectangle().read(s));
793 + }
794 + })
795 + };
796 +
797 + return new type.Component(self, opt);
798 +}
799 +
800 +/**
801 + * @see http://msdn.microsoft.com/en-us/library/cc240644.aspx
802 + * @param opt {object} type option
803 + * @returns {type.Component}
804 + */
805 +function bitmapCompressedDataHeader(opt) {
806 + var self = {
807 + cbCompFirstRowSize : new type.UInt16Le(0x0000, { constant : true }),
808 + // compressed data size
809 + cbCompMainBodySize : new type.UInt16Le(),
810 + cbScanWidth : new type.UInt16Le(),
811 + // uncompressed data size
812 + cbUncompressedSize : new type.UInt16Le()
813 + };
814 +
815 + return new type.Component(self, opt);
816 +}
817 +
818 +/**
819 + * @see
820 + * @param coord {object}
821 + * .destLeft {integer}
822 + * .destTop {integer}
823 + * .destRight {integer}
824 + * .destBottom {integer}
825 + * .width {integer}
826 + * .height {integer}
827 + * .bitsPerPixel {integer}
828 + * .data {Buffer}
829 + * @param opt {object} type option
830 + * @returns {type.Component}
831 + */
832 +function bitmapData(coord, opt) {
833 + coord = coord || {};
834 + var self = {
835 + destLeft : new type.UInt16Le(coord.destLeft),
836 + destTop : new type.UInt16Le(coord.destTop),
837 + destRight : new type.UInt16Le(coord.destRight),
838 + destBottom : new type.UInt16Le(coord.destBottom),
839 + width : new type.UInt16Le(coord.width),
840 + height : new type.UInt16Le(coord.height),
841 + bitsPerPixel : new type.UInt16Le(coord.bitsPerPixel),
842 + flags : new type.UInt16Le(),
843 + bitmapLength : new type.UInt16Le(function() {
844 + return self.bitmapComprHdr.size() + self.bitmapDataStream.size();
845 + }),
846 + bitmapComprHdr : bitmapCompressedDataHeader( { conditional : function() {
847 + return (self.flags.value & BitmapFlag.BITMAP_COMPRESSION) && !(self.flags.value & BitmapFlag.NO_BITMAP_COMPRESSION_HDR);
848 + } }),
849 + bitmapDataStream : new type.BinaryString(coord.data, { readLength : new type.CallableValue(function() {
850 + if(!self.flags.value & BitmapFlag.BITMAP_COMPRESSION || (self.flags.value & BitmapFlag.NO_BITMAP_COMPRESSION_HDR)) {
851 + return self.bitmapLength.value;
852 + }
853 + else {
854 + return self.bitmapComprHdr.cbCompMainBodySize.value;
855 + }
856 + }) })
857 + };
858 +
859 + return new type.Component(self, opt);
860 +}
861 +
862 +/**
863 + * @see http://msdn.microsoft.com/en-us/library/dd306368.aspx
864 + * @param data {type.Component} list of bitmap data type
865 + * @param opt {object} type option
866 + * @returns {type.Component}
867 + */
868 +function bitmapUpdateDataPDU(data, opt) {
869 + var self = {
870 + __UPDATE_TYPE__ : UpdateType.UPDATETYPE_BITMAP,
871 + numberRectangles : new type.UInt16Le(function() {
872 + return self.rectangles.obj.length;
873 + }),
874 + rectangles : data || new type.Factory(function(s) {
875 + self.rectangles = new type.Component([]);
876 + for(var i = 0; i < self.numberRectangles.value; i++) {
877 + self.rectangles.obj.push(bitmapData().read(s));
878 + }
879 + })
880 + };
881 +
882 + return new type.Component(self, opt);
883 +}
884 +
885 +/**
886 + * @see https://msdn.microsoft.com/en-us/library/cc240613.aspx
887 + * @param opt {object} type option
888 + * @returns {type.Component}
889 + */
890 +function synchronizeUpdateDataPDU(opt) {
891 + var self = {
892 + pad2Octets : new type.UInt16Le()
893 + };
894 +
895 + return new type.Component(self, opt);
896 +}
897 +
898 +/**
899 + * @see http://msdn.microsoft.com/en-us/library/cc240608.aspx
900 + * @param updateData {type.Component} update data (ex: bitmapUpdateDataPDU)
901 + * @param opt {object} type option
902 + * @returns {type.Component}
903 + */
904 +function updateDataPDU(updateData, opt) {
905 + var self = {
906 + __PDUTYPE2_ : PDUType2.PDUTYPE2_UPDATE__,
907 + updateType : new type.UInt16Le(function() {
908 + return self.updateData.obj.__UPDATE_TYPE__;
909 + }),
910 + updateData : updateData || new type.Factory(function(s) {
911 + var options = { readLength : new type.CallableValue(function() {
912 + return opt.readLength.value - 2;
913 + })};
914 + switch(self.updateType.value) {
915 + case UpdateType.UPDATETYPE_BITMAP:
916 + self.updateData = bitmapUpdateDataPDU(null, options).read(s);
917 + break;
918 + case UpdateType.UPDATETYPE_SYNCHRONIZE:
919 + // do nothing artefact of protocol
920 + self.updateData = synchronizeUpdateDataPDU(null, options).read(s);
921 + break;
922 + default:
923 + self.updateData = new type.BinaryString(null, options).read(s);
924 + log.debug('unknown updateDataPDU ' + self.updateType.value);
925 + }
926 + })
927 + };
928 +
929 + return new type.Component(self, opt);
930 +}
931 +
932 +/**
933 + * @param pduData {type.Component}
934 + * @param shareId {integer}
935 + * @param opt {object} type option
936 + * @returns {type.Component}
937 + */
938 +function dataPDU(pduData, shareId, opt) {
939 + var self = {
940 + __PDUTYPE__ : PDUType.PDUTYPE_DATAPDU,
941 + shareDataHeader : shareDataHeader(new type.CallableValue(function() {
942 + return new type.Component(self).size();
943 + }), function() {
944 + return self.pduData.obj.__PDUTYPE2__;
945 + }, shareId),
946 + pduData : pduData || new type.Factory(function(s) {
947 +
948 + //compute local readLength
949 + var options = { readLength : new type.CallableValue(function() {
950 + return opt.readLength.value - self.shareDataHeader.size();
951 + }) };
952 +
953 + switch(self.shareDataHeader.obj.pduType2.value) {
954 + case PDUType2.PDUTYPE2_SYNCHRONIZE:
955 + self.pduData = synchronizeDataPDU(null, options).read(s)
956 + break;
957 + case PDUType2.PDUTYPE2_CONTROL:
958 + self.pduData = controlDataPDU(null, options).read(s);
959 + break;
960 + case PDUType2.PDUTYPE2_SET_ERROR_INFO_PDU:
961 + self.pduData = errorInfoDataPDU(null, options).read(s);
962 + break;
963 + case PDUType2.PDUTYPE2_FONTLIST:
964 + self.pduData = fontListDataPDU(options).read(s);
965 + break;
966 + case PDUType2.PDUTYPE2_FONTMAP:
967 + self.pduData = fontMapDataPDU(options).read(s);
968 + break;
969 + case PDUType2.PDUTYPE2_BITMAPCACHE_PERSISTENT_LIST:
970 + self.pduData = persistentListPDU(null, options).read(s);
971 + break;
972 + case PDUType2.PDUTYPE2_INPUT:
973 + self.pduData = clientInputEventPDU(null, options).read(s);
974 + break;
975 + case PDUType2.PDUTYPE2_SHUTDOWN_REQUEST:
976 + self.pduData = shutdownRequestPDU(options).read(s);
977 + break;
978 + case PDUType2.PDUTYPE2_SHUTDOWN_DENIED:
979 + self.pduData = shutdownDeniedPDU(options).read(s);
980 + break;
981 + case PDUType2.PDUTYPE2_SUPPRESS_OUTPUT:
982 + self.pduData = supressOutputDataPDU(options).read(s);
983 + break;
984 + case PDUType2.PDUTYPE2_REFRESH_RECT:
985 + self.pduData = refreshRectPDU(null, options).read(s);
986 + break;
987 + case PDUType2.PDUTYPE2_UPDATE:
988 + self.pduData = updateDataPDU(null, options).read(s);
989 + break;
990 + default:
991 + self.pduData = new type.BinaryString(null, options).read(s);
992 + log.debug('unknown PDUType2 ' + self.shareDataHeader.obj.pduType2.value);
993 + }
994 + })
995 + };
996 +
997 + return new type.Component(self, opt);
998 +}
999 +
1000 +/**
1001 + * @param userId {integer}
1002 + * @param pduMessage {type.Component} pdu message
1003 + * @param opt {object} type option
1004 + * @returns {type.Component}
1005 + */
1006 +function pdu(userId, pduMessage, opt) {
1007 + var self = {
1008 + shareControlHeader : shareControlHeader(function() {
1009 + return new type.Component(self).size();
1010 + }, function() {
1011 + return pduMessage.obj.__PDUTYPE__;
1012 + }, userId),
1013 + pduMessage : pduMessage || new type.Factory(function(s) {
1014 +
1015 + // compute local common options
1016 + var options = { readLength : new type.CallableValue(function() {
1017 + return self.shareControlHeader.obj.totalLength.value - self.shareControlHeader.size();
1018 + }) };
1019 +
1020 + switch(self.shareControlHeader.obj.pduType.value) {
1021 + case PDUType.PDUTYPE_DEMANDACTIVEPDU:
1022 + self.pduMessage = demandActivePDU(null, options).read(s);
1023 + break;
1024 + case PDUType.PDUTYPE_CONFIRMACTIVEPDU:
1025 + self.pduMessage = confirmActivePDU(null, options).read(s);
1026 + break;
1027 + case PDUType.PDUTYPE_DEACTIVATEALLPDU:
1028 + self.pduMessage = deactiveAllPDU(options).read(s);
1029 + break;
1030 + case PDUType.PDUTYPE_DATAPDU:
1031 + self.pduMessage = dataPDU(null, null, options).read(s);
1032 + break;
1033 + default:
1034 + self.pduMessage = new type.BinaryString(null, options).read(s);
1035 + log.debug('unknown pdu type ' + self.shareControlHeader.obj.pduType.value);
1036 + }
1037 + })
1038 + };
1039 +
1040 + return new type.Component(self, opt);
1041 +}
1042 +
1043 +/**
1044 + * @see http://msdn.microsoft.com/en-us/library/dd306368.aspx
1045 + * @param opt {object} type option
1046 + * @returns {type.Component}
1047 + */
1048 +function fastPathBitmapUpdateDataPDU (opt) {
1049 + var self = {
1050 + __FASTPATH_UPDATE_TYPE__ : FastPathUpdateType.FASTPATH_UPDATETYPE_BITMAP,
1051 + header : new type.UInt16Le(FastPathUpdateType.FASTPATH_UPDATETYPE_BITMAP, { constant : true }),
1052 + numberRectangles : new type.UInt16Le( function () {
1053 + return self.rectangles.obj.length;
1054 + }),
1055 + rectangles : new type.Factory( function (s) {
1056 + self.rectangles = new type.Component([]);
1057 + for(var i = 0; i < self.numberRectangles.value; i++) {
1058 + self.rectangles.obj.push(bitmapData().read(s));
1059 + }
1060 + })
1061 + };
1062 +
1063 + return new type.Component(self, opt);
1064 +}
1065 +
1066 +/**
1067 + * @see http://msdn.microsoft.com/en-us/library/cc240622.aspx
1068 + * @param updateData {type.Component}
1069 + * @param opt {object} type option
1070 + * @returns {type.Component}
1071 + */
1072 +function fastPathUpdatePDU (updateData, opt) {
1073 + var self = {
1074 + updateHeader : new type.UInt8( function () {
1075 + return self.updateData.obj.__FASTPATH_UPDATE_TYPE__;
1076 + }),
1077 + compressionFlags : new type.UInt8(null, { conditional : function () {
1078 + return (self.updateHeader.value >> 4) & FastPathOutputCompression.FASTPATH_OUTPUT_COMPRESSION_USED;
1079 + }}),
1080 + size : new type.UInt16Le( function () {
1081 + return self.updateData.size();
1082 + }),
1083 + updateData : updateData || new type.Factory( function (s) {
1084 + var options = { readLength : new type.CallableValue( function () {
1085 + return self.size.value;
1086 + }) };
1087 +
1088 + switch (self.updateHeader.value & 0xf) {
1089 + case FastPathUpdateType.FASTPATH_UPDATETYPE_BITMAP:
1090 + self.updateData = fastPathBitmapUpdateDataPDU(options).read(s);
1091 + break;
1092 + default:
1093 + self.updateData = new type.BinaryString(null, options).read(s);
1094 + log.debug('unknown fast path pdu type ' + (self.updateHeader.value & 0xf));
1095 + }
1096 + })
1097 + };
1098 +
1099 + return new type.Component(self, opt);
1100 +}
1101 +
1102 +/**
1103 + * Module exports
1104 + */
1105 +module.exports = {
1106 + PDUType : PDUType,
1107 + PDUType2 : PDUType2,
1108 + StreamId : StreamId,
1109 + CompressionOrder : CompressionOrder,
1110 + CompressionType : CompressionType,
1111 + Action : Action,
1112 + PersistentKeyListFlag : PersistentKeyListFlag,
1113 + BitmapFlag : BitmapFlag,
1114 + UpdateType : UpdateType,
1115 + InputMessageType : InputMessageType,
1116 + PointerFlag : PointerFlag,
1117 + KeyboardFlag : KeyboardFlag,
1118 + FastPathOutputCompression : FastPathOutputCompression,
1119 + Display : Display,
1120 + ToogleFlag : ToogleFlag,
1121 + ErrorInfo : ErrorInfo,
1122 + FastPathUpdateType : FastPathUpdateType,
1123 + shareControlHeader : shareControlHeader,
1124 + shareDataHeader : shareDataHeader,
1125 + demandActivePDU : demandActivePDU,
1126 + confirmActivePDU : confirmActivePDU,
1127 + deactiveAllPDU : deactiveAllPDU,
1128 + pdu : pdu,
1129 + synchronizeDataPDU : synchronizeDataPDU,
1130 + controlDataPDU : controlDataPDU,
1131 + errorInfoDataPDU : errorInfoDataPDU,
1132 + fontListDataPDU : fontListDataPDU,
1133 + fontMapDataPDU : fontMapDataPDU,
1134 + persistentListPDU : persistentListPDU,
1135 + synchronizeEvent : synchronizeEvent,
1136 + pointerEvent : pointerEvent,
1137 + scancodeKeyEvent : scancodeKeyEvent,
1138 + unicodeKeyEvent : unicodeKeyEvent,
1139 + slowPathInputEvent : slowPathInputEvent,
1140 + clientInputEventPDU : clientInputEventPDU,
1141 + shutdownRequestPDU : shutdownRequestPDU,
1142 + shutdownDeniedPDU : shutdownDeniedPDU,
1143 + supressOutputDataPDU : supressOutputDataPDU,
1144 + refreshRectPDU : refreshRectPDU,
1145 + bitmapData : bitmapData,
1146 + bitmapUpdateDataPDU : bitmapUpdateDataPDU,
1147 + updateDataPDU : updateDataPDU,
1148 + dataPDU : dataPDU,
1149 + fastPathBitmapUpdateDataPDU : fastPathBitmapUpdateDataPDU,
1150 + fastPathUpdatePDU : fastPathUpdatePDU
1151 +};
\ No newline at end of file
rdp/protocol/pdu/global.js new
+402
@@ -0,0 +1,402 @@
1 +/*
2 + * Copyright (c) 2014-2015 Sylvain Peyrefitte
3 + *
4 + * This file is part of node-rdpjs.
5 + *
6 + * node-rdpjs is free software: you can redistribute it and/or modify
7 + * it under the terms of the GNU General Public License as published by
8 + * the Free Software Foundation, either version 3 of the License, or
9 + * (at your option) any later version.
10 + *
11 + * This program is distributed in the hope that it will be useful,
12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 + * GNU General Public License for more details.
15 + *
16 + * You should have received a copy of the GNU General Public License
17 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 + */
19 +
20 +var inherits = require('util').inherits;
21 +var events = require('events');
22 +var caps = require('./caps');
23 +var data = require('./data');
24 +var type = require('../../core').type;
25 +var log = require('../../core').log;
26 +
27 +/**
28 + * Global channel for all graphic updates
29 + * capabilities exchange and input handles
30 + */
31 +function Global(transport, fastPathTransport) {
32 + this.transport = transport;
33 + this.fastPathTransport = fastPathTransport;
34 + // must be init via connect event
35 + this.userId = 0;
36 + this.serverCapabilities = [];
37 + this.clientCapabilities = [];
38 +}
39 +
40 +//inherit from Layer
41 +inherits(Global, events.EventEmitter);
42 +
43 +/**
44 + * Send formated PDU message
45 + * @param message {type.Component} PDU message
46 + */
47 +Global.prototype.sendPDU = function(message) {
48 + this.transport.send(data.pdu(this.userId, message));
49 +};
50 +
51 +/**
52 + * Send formated Data PDU message
53 + * @param message {type.Component} PDU message
54 + */
55 +Global.prototype.sendDataPDU = function(message) {
56 + this.sendPDU(data.dataPDU(message, this.shareId));
57 +};
58 +
59 +/**
60 + * Client side of Global channel automata
61 + * @param transport
62 + */
63 +function Client(transport, fastPathTransport) {
64 + Global.call(this, transport, fastPathTransport);
65 + var self = this;
66 + this.transport.once('connect', function(core, userId, channelId) {
67 + self.connect(core, userId, channelId);
68 + }).on('close', function() {
69 + self.emit('close');
70 + }).on('error', function (err) {
71 + self.emit('error', err);
72 + });
73 +
74 + if (this.fastPathTransport) {
75 + this.fastPathTransport.on('fastPathData', function (secFlag, s) {
76 + self.recvFastPath(secFlag, s);
77 + });
78 + }
79 +
80 + // init client capabilities
81 + this.clientCapabilities[caps.CapsType.CAPSTYPE_GENERAL] = caps.generalCapability();
82 + this.clientCapabilities[caps.CapsType.CAPSTYPE_BITMAP] = caps.bitmapCapability();
83 + this.clientCapabilities[caps.CapsType.CAPSTYPE_ORDER] = caps.orderCapability(
84 + new type.Component([
85 + new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0),
86 + new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0),
87 + new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0),
88 + new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0)
89 + ]));
90 + this.clientCapabilities[caps.CapsType.CAPSTYPE_BITMAPCACHE] = caps.bitmapCacheCapability();
91 + this.clientCapabilities[caps.CapsType.CAPSTYPE_POINTER] = caps.pointerCapability();
92 + this.clientCapabilities[caps.CapsType.CAPSTYPE_INPUT] = caps.inputCapability();
93 + this.clientCapabilities[caps.CapsType.CAPSTYPE_BRUSH] = caps.brushCapability();
94 + this.clientCapabilities[caps.CapsType.CAPSTYPE_GLYPHCACHE] = caps.glyphCapability(
95 + new type.Component([
96 + caps.cacheEntry(), caps.cacheEntry(), caps.cacheEntry(), caps.cacheEntry(), caps.cacheEntry(),
97 + caps.cacheEntry(), caps.cacheEntry(), caps.cacheEntry(), caps.cacheEntry(), caps.cacheEntry()
98 + ]));
99 + this.clientCapabilities[caps.CapsType.CAPSTYPE_OFFSCREENCACHE] = caps.offscreenBitmapCacheCapability();
100 + this.clientCapabilities[caps.CapsType.CAPSTYPE_VIRTUALCHANNEL] = caps.virtualChannelCapability();
101 + this.clientCapabilities[caps.CapsType.CAPSTYPE_SOUND] = caps.soundCapability();
102 + this.clientCapabilities[caps.CapsType.CAPSETTYPE_MULTIFRAGMENTUPDATE] = caps.multiFragmentUpdate();
103 +}
104 +
105 +// inherit from Layer
106 +inherits(Client, Global);
107 +
108 +/**
109 + * connect function
110 + * @param gccCore {type.Component(clientCoreData)}
111 + */
112 +Client.prototype.connect = function(gccCore, userId, channelId) {
113 + this.gccCore = gccCore;
114 + this.userId = userId;
115 + this.channelId = channelId;
116 + var self = this;
117 + this.transport.once('data', function(s) {
118 + self.recvDemandActivePDU(s);
119 + });
120 +};
121 +
122 +/**
123 + * close stack
124 + */
125 +Client.prototype.close = function() {
126 + this.transport.close();
127 +};
128 +
129 +/**
130 + * Receive capabilities from server
131 + * @param s {type.Stream}
132 + */
133 +Client.prototype.recvDemandActivePDU = function(s) {
134 + var pdu = data.pdu().read(s);
135 + if (pdu.obj.shareControlHeader.obj.pduType.value !== data.PDUType.PDUTYPE_DEMANDACTIVEPDU) {
136 + log.debug('ignore message type ' + pdu.obj.shareControlHeader.obj.pduType.value + ' during connection sequence');
137 +
138 + // loop on state
139 + var self = this;
140 + this.transport.once('data', function(s) {
141 + self.recvDemandActivePDU(s);
142 + });
143 + return;
144 + }
145 +
146 + // store share id
147 + this.shareId = pdu.obj.pduMessage.obj.shareId.value;
148 +
149 + // store server capabilities
150 + for(var i in pdu.obj.pduMessage.obj.capabilitySets.obj) {
151 + var cap = pdu.obj.pduMessage.obj.capabilitySets.obj[i].obj.capability;
152 + if(!cap.obj) {
153 + continue;
154 + }
155 + this.serverCapabilities[cap.obj.__TYPE__] = cap;
156 + }
157 +
158 + this.transport.enableSecureCheckSum = !!(this.serverCapabilities[caps.CapsType.CAPSTYPE_GENERAL].obj.extraFlags.value & caps.GeneralExtraFlag.ENC_SALTED_CHECKSUM);
159 +
160 + this.sendConfirmActivePDU();
161 + this.sendClientFinalizeSynchronizePDU();
162 +
163 + var self = this;
164 + this.transport.once('data', function(s) {
165 + self.recvServerSynchronizePDU(s);
166 + });
167 +};
168 +
169 +/**
170 + * global channel automata state
171 + * @param s {type.Stream}
172 + */
173 +Client.prototype.recvServerSynchronizePDU = function(s) {
174 + var pdu = data.pdu().read(s);
175 + if ( pdu.obj.shareControlHeader.obj.pduType.value !== data.PDUType.PDUTYPE_DATAPDU
176 + || pdu.obj.pduMessage.obj.shareDataHeader.obj.pduType2.value !== data.PDUType2.PDUTYPE2_SYNCHRONIZE) {
177 + log.debug('ignore message type ' + pdu.obj.shareControlHeader.obj.pduType.value + ' during connection sequence');
178 + // loop on state
179 + var self = this;
180 + this.transport.once('data', function(s) {
181 + self.recvServerSynchronizePDU(s);
182 + });
183 + return;
184 + }
185 +
186 + var self = this;
187 + this.transport.once('data', function(s) {
188 + self.recvServerControlCooperatePDU(s);
189 + });
190 +};
191 +
192 +/**
193 + * global channel automata state
194 + * @param s {type.Stream}
195 + */
196 +Client.prototype.recvServerControlCooperatePDU = function(s) {
197 + var pdu = data.pdu().read(s);
198 + if ( pdu.obj.shareControlHeader.obj.pduType.value !== data.PDUType.PDUTYPE_DATAPDU
199 + || pdu.obj.pduMessage.obj.shareDataHeader.obj.pduType2.value !== data.PDUType2.PDUTYPE2_CONTROL
200 + || pdu.obj.pduMessage.obj.pduData.obj.action.value !== data.Action.CTRLACTION_COOPERATE) {
201 + log.debug('ignore message type ' + pdu.obj.shareControlHeader.obj.pduType.value + ' during connection sequence');
202 +
203 + // loop on state
204 + var self = this;
205 + this.transport.once('data', function(s) {
206 + self.recvServerControlCooperatePDU(s);
207 + });
208 + }
209 +
210 + var self = this;
211 + this.transport.once('data', function(s) {
212 + self.recvServerControlGrantedPDU(s);
213 + });
214 +};
215 +
216 +/**
217 + * global channel automata state
218 + * @param s {type.Stream}
219 + */
220 +Client.prototype.recvServerControlGrantedPDU = function(s) {
221 + var pdu = data.pdu().read(s);
222 + if ( pdu.obj.shareControlHeader.obj.pduType.value !== data.PDUType.PDUTYPE_DATAPDU
223 + || pdu.obj.pduMessage.obj.shareDataHeader.obj.pduType2.value !== data.PDUType2.PDUTYPE2_CONTROL
224 + || pdu.obj.pduMessage.obj.pduData.obj.action.value !== data.Action.CTRLACTION_GRANTED_CONTROL) {
225 + log.debug('ignore message type ' + pdu.obj.shareControlHeader.obj.pduType.value + ' during connection sequence');
226 +
227 + // loop on state
228 + var self = this;
229 + this.transport.once('data', function(s) {
230 + self.recvServerControlGrantedPDU(s);
231 + });
232 + }
233 +
234 + var self = this;
235 + this.transport.once('data', function(s) {
236 + self.recvServerFontMapPDU(s);
237 + });
238 +};
239 +
240 +/**
241 + * global channel automata state
242 + * @param s {type.Stream}
243 + */
244 +Client.prototype.recvServerFontMapPDU = function(s) {
245 + var pdu = data.pdu().read(s);
246 + if ( pdu.obj.shareControlHeader.obj.pduType.value !== data.PDUType.PDUTYPE_DATAPDU
247 + || pdu.obj.pduMessage.obj.shareDataHeader.obj.pduType2.value !== data.PDUType2.PDUTYPE2_FONTMAP) {
248 + log.debug('ignore message type ' + pdu.obj.shareControlHeader.obj.pduType.value + ' during connection sequence');
249 +
250 + // loop on state
251 + var self = this;
252 + this.transport.once('data', function(s) {
253 + self.recvServerFontMapPDU(s);
254 + });
255 + }
256 +
257 + this.emit('connect');
258 + var self = this;
259 + this.transport.on('data', function(s) {
260 + self.recvPDU(s);
261 + });
262 +};
263 +
264 +/**
265 + * Main reveive fast path
266 + * @param secFlag {integer}
267 + * @param s {type.Stream}
268 + */
269 +Client.prototype.recvFastPath = function (secFlag, s) {
270 + while (s.availableLength() > 0) {
271 + var pdu = data.fastPathUpdatePDU().read(s);
272 + switch (pdu.obj.updateHeader.value & 0xf) {
273 + case data.FastPathUpdateType.FASTPATH_UPDATETYPE_BITMAP:
274 + this.emit('bitmap', pdu.obj.updateData.obj.rectangles.obj);
275 + break;
276 + default:
277 + }
278 + }
279 +};
280 +
281 +/**
282 + * global channel automata state
283 + * @param s {type.Stream}
284 + */
285 +Client.prototype.recvPDU = function(s) {
286 + while (s.availableLength() > 0) {
287 + var pdu = data.pdu().read(s);
288 + switch(pdu.obj.shareControlHeader.obj.pduType.value) {
289 + case data.PDUType.PDUTYPE_DEACTIVATEALLPDU:
290 + var self = this;
291 + this.transport.removeAllListeners('data');
292 + this.transport.once('data', function(s) {
293 + self.recvDemandActivePDU(s);
294 + });
295 + break;
296 + case data.PDUType.PDUTYPE_DATAPDU:
297 + this.readDataPDU(pdu.obj.pduMessage)
298 + break;
299 + default:
300 + log.debug('ignore pdu type ' + pdu.obj.shareControlHeader.obj.pduType.value);
301 + }
302 + }
303 +};
304 +
305 +/**
306 + * main receive for data PDU packet
307 + * @param dataPDU {data.dataPDU}
308 + */
309 +Client.prototype.readDataPDU = function (dataPDU) {
310 + switch(dataPDU.obj.shareDataHeader.obj.pduType2.value) {
311 + case data.PDUType2.PDUTYPE2_SET_ERROR_INFO_PDU:
312 + break;
313 + case data.PDUType2.PDUTYPE2_SHUTDOWN_DENIED:
314 + this.transport.close();
315 + break;
316 + case data.PDUType2.PDUTYPE2_SAVE_SESSION_INFO:
317 + this.emit('session');
318 + break;
319 + case data.PDUType2.PDUTYPE2_UPDATE:
320 + this.readUpdateDataPDU(dataPDU.obj.pduData)
321 + break;
322 + }
323 +};
324 +
325 +/**
326 + * Main upadate pdu receive function
327 + * @param updateDataPDU
328 + */
329 +Client.prototype.readUpdateDataPDU = function (updateDataPDU) {
330 + switch(updateDataPDU.obj.updateType.value) {
331 + case data.UpdateType.UPDATETYPE_BITMAP:
332 + this.emit('bitmap', updateDataPDU.obj.updateData.obj.rectangles.obj)
333 + break;
334 + }
335 +};
336 +
337 +/**
338 + * send all client capabilities
339 + */
340 +Client.prototype.sendConfirmActivePDU = function () {
341 + var generalCapability = this.clientCapabilities[caps.CapsType.CAPSTYPE_GENERAL].obj;
342 + generalCapability.osMajorType.value = caps.MajorType.OSMAJORTYPE_WINDOWS;
343 + generalCapability.osMinorType.value = caps.MinorType.OSMINORTYPE_WINDOWS_NT;
344 + generalCapability.extraFlags.value = caps.GeneralExtraFlag.LONG_CREDENTIALS_SUPPORTED
345 + | caps.GeneralExtraFlag.NO_BITMAP_COMPRESSION_HDR
346 + | caps.GeneralExtraFlag.ENC_SALTED_CHECKSUM
347 + | caps.GeneralExtraFlag.FASTPATH_OUTPUT_SUPPORTED;
348 +
349 + var bitmapCapability = this.clientCapabilities[caps.CapsType.CAPSTYPE_BITMAP].obj;
350 + bitmapCapability.preferredBitsPerPixel.value = this.gccCore.highColorDepth.value;
351 + bitmapCapability.desktopWidth.value = this.gccCore.desktopWidth.value;
352 + bitmapCapability.desktopHeight.value = this.gccCore.desktopHeight.value;
353 +
354 + var orderCapability = this.clientCapabilities[caps.CapsType.CAPSTYPE_ORDER].obj;
355 + orderCapability.orderFlags.value |= caps.OrderFlag.ZEROBOUNDSDELTASSUPPORT;
356 +
357 + var inputCapability = this.clientCapabilities[caps.CapsType.CAPSTYPE_INPUT].obj;
358 + inputCapability.inputFlags.value = caps.InputFlags.INPUT_FLAG_SCANCODES | caps.InputFlags.INPUT_FLAG_MOUSEX | caps.InputFlags.INPUT_FLAG_UNICODE;
359 + inputCapability.keyboardLayout = this.gccCore.kbdLayout;
360 + inputCapability.keyboardType = this.gccCore.keyboardType;
361 + inputCapability.keyboardSubType = this.gccCore.keyboardSubType;
362 + inputCapability.keyboardrFunctionKey = this.gccCore.keyboardFnKeys;
363 + inputCapability.imeFileName = this.gccCore.imeFileName;
364 +
365 + var capabilities = new type.Component([]);
366 + for(var i in this.clientCapabilities) {
367 + capabilities.obj.push(caps.capability(this.clientCapabilities[i]));
368 + }
369 +
370 + var confirmActivePDU = data.confirmActivePDU(capabilities, this.shareId);
371 +
372 + this.sendPDU(confirmActivePDU);
373 +};
374 +
375 +/**
376 + * send synchronize PDU
377 + */
378 +Client.prototype.sendClientFinalizeSynchronizePDU = function() {
379 + this.sendDataPDU(data.synchronizeDataPDU(this.channelId));
380 + this.sendDataPDU(data.controlDataPDU(data.Action.CTRLACTION_COOPERATE));
381 + this.sendDataPDU(data.controlDataPDU(data.Action.CTRLACTION_REQUEST_CONTROL));
382 + this.sendDataPDU(data.fontListDataPDU());
383 +};
384 +
385 +/**
386 + * Send input event as slow path input
387 + * @param inputEvents {array}
388 + */
389 +Client.prototype.sendInputEvents = function (inputEvents) {
390 + var pdu = data.clientInputEventPDU(new type.Component(inputEvents.map(function (e) {
391 + return data.slowPathInputEvent(e);
392 + })));
393 +
394 + this.sendDataPDU(pdu);
395 +};
396 +
397 +/**
398 + * Module exports
399 + */
400 +module.exports = {
401 + Client : Client
402 +};
\ No newline at end of file
rdp/protocol/pdu/index.js new
+30
@@ -0,0 +1,30 @@
1 +/*
2 + * Copyright (c) 2014-2015 Sylvain Peyrefitte
3 + *
4 + * This file is part of node-rdpjs.
5 + *
6 + * node-rdpjs is free software: you can redistribute it and/or modify
7 + * it under the terms of the GNU General Public License as published by
8 + * the Free Software Foundation, either version 3 of the License, or
9 + * (at your option) any later version.
10 + *
11 + * This program is distributed in the hope that it will be useful,
12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 + * GNU General Public License for more details.
15 + *
16 + * You should have received a copy of the GNU General Public License
17 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 + */
19 +
20 +var lic = require('./lic');
21 +var sec = require('./sec');
22 +var global = require('./global');
23 +var data = require('./data');
24 +
25 +module.exports = {
26 + lic : lic,
27 + sec : sec,
28 + global : global,
29 + data : data
30 +};
rdp/protocol/pdu/lic.js new
+309
@@ -0,0 +1,309 @@
1 +/*
2 + * Copyright (c) 2014-2015 Sylvain Peyrefitte
3 + *
4 + * This file is part of node-rdpjs.
5 + *
6 + * node-rdpjs is free software: you can redistribute it and/or modify
7 + * it under the terms of the GNU General Public License as published by
8 + * the Free Software Foundation, either version 3 of the License, or
9 + * (at your option) any later version.
10 + *
11 + * This program is distributed in the hope that it will be useful,
12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 + * GNU General Public License for more details.
15 + *
16 + * You should have received a copy of the GNU General Public License
17 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 + */
19 +
20 +var type = require('../../core').type;
21 +
22 +var MessageType = {
23 + LICENSE_REQUEST : 0x01,
24 + PLATFORM_CHALLENGE : 0x02,
25 + NEW_LICENSE : 0x03,
26 + UPGRADE_LICENSE : 0x04,
27 + LICENSE_INFO : 0x12,
28 + NEW_LICENSE_REQUEST : 0x13,
29 + PLATFORM_CHALLENGE_RESPONSE : 0x15,
30 + ERROR_ALERT : 0xFF
31 +};
32 +
33 +/**
34 + * @see http://msdn.microsoft.com/en-us/library/cc240482.aspx
35 + */
36 +var ErrorCode = {
37 + ERR_INVALID_SERVER_CERTIFICATE : 0x00000001,
38 + ERR_NO_LICENSE : 0x00000002,
39 + ERR_INVALID_SCOPE : 0x00000004,
40 + ERR_NO_LICENSE_SERVER : 0x00000006,
41 + STATUS_VALID_CLIENT : 0x00000007,
42 + ERR_INVALID_CLIENT : 0x00000008,
43 + ERR_INVALID_PRODUCTID : 0x0000000B,
44 + ERR_INVALID_MESSAGE_LEN : 0x0000000C,
45 + ERR_INVALID_MAC : 0x00000003
46 +};
47 +
48 +/**
49 + * @see http://msdn.microsoft.com/en-us/library/cc240482.aspx
50 + */
51 +var StateTransition = {
52 + ST_TOTAL_ABORT : 0x00000001,
53 + ST_NO_TRANSITION : 0x00000002,
54 + ST_RESET_PHASE_TO_START : 0x00000003,
55 + ST_RESEND_LAST_MESSAGE : 0x00000004
56 +};
57 +
58 +/**
59 + * @see http://msdn.microsoft.com/en-us/library/cc240481.aspx
60 + */
61 +var BinaryBlobType = {
62 + BB_ANY_BLOB : 0x0000,
63 + BB_DATA_BLOB : 0x0001,
64 + BB_RANDOM_BLOB : 0x0002,
65 + BB_CERTIFICATE_BLOB : 0x0003,
66 + BB_ERROR_BLOB : 0x0004,
67 + BB_ENCRYPTED_DATA_BLOB : 0x0009,
68 + BB_KEY_EXCHG_ALG_BLOB : 0x000D,
69 + BB_SCOPE_BLOB : 0x000E,
70 + BB_CLIENT_USER_NAME_BLOB : 0x000F,
71 + BB_CLIENT_MACHINE_NAME_BLOB : 0x0010
72 +};
73 +
74 +var Preambule = {
75 + PREAMBLE_VERSION_2_0 : 0x2,
76 + PREAMBLE_VERSION_3_0 : 0x3,
77 + EXTENDED_ERROR_MSG_SUPPORTED : 0x80
78 +};
79 +
80 +/**
81 + * Binary blob to emcompass license information
82 + * @see http://msdn.microsoft.com/en-us/library/cc240481.aspx
83 + * @param blobType {BinaryBlobType.*}
84 + * @returns {type.Component}
85 + */
86 +function licenseBinaryBlob(blobType) {
87 + blobType = blobType || BinaryBlobType.BB_ANY_BLOB;
88 + var self = {
89 + wBlobType : new type.UInt16Le(blobType, { constant : (blobType === BinaryBlobType.BB_ANY_BLOB)?false:true }),
90 + wBlobLen : new type.UInt16Le(function() {
91 + return self.blobData.size();
92 + }),
93 + blobData : new type.BinaryString(null, { readLength : new type.CallableValue(function() {
94 + return self.wBlobLen.value;
95 + })})
96 + };
97 +
98 + return new type.Component(self);
99 +}
100 +
101 +/**
102 + * Error message in license PDU automata
103 + * @see http://msdn.microsoft.com/en-us/library/cc240482.aspx
104 + * @param opt {object} type options
105 + * @returns {type.Component}
106 + */
107 +function licensingErrorMessage(opt) {
108 + var self = {
109 + __TYPE__ : MessageType.ERROR_ALERT,
110 + dwErrorCode : new type.UInt32Le(),
111 + dwStateTransition : new type.UInt32Le(),
112 + blob : licenseBinaryBlob(BinaryBlobType.BB_ANY_BLOB)
113 + };
114 +
115 + return new type.Component(self, opt);
116 +}
117 +
118 +/**
119 + * License product informations
120 + * @see http://msdn.microsoft.com/en-us/library/cc241915.aspx
121 + * @returns {type.Component}
122 + */
123 +function productInformation() {
124 + var self = {
125 + dwVersion : new type.UInt32Le(),
126 + cbCompanyName : new type.UInt32Le(function() {
127 + return self.pbCompanyName.size();
128 + }),
129 + // may contain "Microsoft Corporation" from server microsoft
130 + pbCompanyName : new type.BinaryString(Buffer.from('Microsoft Corporation', 'ucs2'), { readLength : new type.CallableValue(function() {
131 + return self.cbCompanyName.value;
132 + })}),
133 + cbProductId : new type.UInt32Le(function() {
134 + return self.pbProductId.size();
135 + }),
136 + // may contain "A02" from microsoft license server
137 + pbProductId : new type.BinaryString(Buffer.from('A02', 'ucs2'), { readLength : new type.CallableValue(function() {
138 + return self.cbProductId.value;
139 + })})
140 + };
141 +
142 + return new type.Component(self);
143 +}
144 +
145 +/**
146 + * Use in license negotiation
147 + * @see http://msdn.microsoft.com/en-us/library/cc241917.aspx
148 + * @returns {type.Component}
149 + */
150 +function scope() {
151 + var self = {
152 + scope : licenseBinaryBlob(BinaryBlobType.BB_SCOPE_BLOB)
153 + };
154 +
155 + return new type.Component(self);
156 +}
157 +
158 +/**
159 + * @see http://msdn.microsoft.com/en-us/library/cc241916.aspx
160 + * @returns {type.Component}
161 + */
162 +function scopeList() {
163 + var self = {
164 + scopeCount : new type.UInt32Le(function() {
165 + return self.scopeArray.length;
166 + }),
167 + scopeArray : new type.Factory(function(s) {
168 + self.scopeArray = new type.Component([]);
169 + for(var i = 0; i < self.scopeCount.value; i++) {
170 + self.scopeArray.obj.push(scope().read(s));
171 + }
172 + })
173 + };
174 +
175 + return new type.Component(self);
176 +}
177 +
178 +/**
179 + * @see http://msdn.microsoft.com/en-us/library/cc241914.aspx
180 + * @param opt {object} type options
181 + * @returns {type.Component}
182 + */
183 +function serverLicenseRequest(opt) {
184 + var self = {
185 + __TYPE__ : MessageType.LICENSE_REQUEST,
186 + serverRandom : new type.BinaryString(Buffer.from(Array(32 + 1).join('\x00')), { readLength : new type.CallableValue(32) } ),
187 + productInfo : productInformation(),
188 + keyExchangeList : licenseBinaryBlob(BinaryBlobType.BB_KEY_EXCHG_ALG_BLOB),
189 + serverCertificate : licenseBinaryBlob(BinaryBlobType.BB_CERTIFICATE_BLOB),
190 + scopeList : scopeList()
191 + };
192 +
193 + return new type.Component(self, opt);
194 +}
195 +
196 +/**
197 + * @see http://msdn.microsoft.com/en-us/library/cc241918.aspx
198 + * @param opt {object} type options
199 + * @returns {type.Component}
200 + */
201 +function clientNewLicenseRequest(opt) {
202 + var self = {
203 + __TYPE__ : MessageType.NEW_LICENSE_REQUEST,
204 + preferredKeyExchangeAlg : new type.UInt32Le(0x00000001, { constant : true }),
205 + // pure microsoft client ;-)
206 + // http://msdn.microsoft.com/en-us/library/1040af38-c733-4fb3-acd1-8db8cc979eda#id10
207 + platformId : new type.UInt32Le(0x04000000 | 0x00010000),
208 + clientRandom : new type.BinaryString(Buffer.from(Array(32 + 1).join('\x00')), { readLength : new type.CallableValue(32) }),
209 + encryptedPreMasterSecret : licenseBinaryBlob(BinaryBlobType.BB_RANDOM_BLOB),
210 + ClientUserName : licenseBinaryBlob(BinaryBlobType.BB_CLIENT_USER_NAME_BLOB),
211 + ClientMachineName : licenseBinaryBlob(BinaryBlobType.BB_CLIENT_MACHINE_NAME_BLOB)
212 + };
213 +
214 + return new type.Component(self, opt);
215 +}
216 +
217 +/**
218 + * @see http://msdn.microsoft.com/en-us/library/cc241921.aspx
219 + * @param opt {object} type options
220 + * @returns {type.Component}
221 + */
222 +function serverPlatformChallenge(opt) {
223 + var self = {
224 + __TYPE__ : MessageType.PLATFORM_CHALLENGE,
225 + connectFlags : new type.UInt32Le(),
226 + encryptedPlatformChallenge : licenseBinaryBlob(BinaryBlobType.BB_ANY_BLOB),
227 + MACData : new type.BinaryString(Buffer.from(Array(16 + 1).join('\x00')), { readLength : new type.CallableValue(16) })
228 + };
229 +
230 + return new type.Component(self, opt);
231 +}
232 +
233 +/**
234 + * @see http://msdn.microsoft.com/en-us/library/cc241922.aspx
235 + * @param opt {object} type options
236 + * @returns {type.Component}
237 + */
238 +function clientPLatformChallengeResponse(opt) {
239 + var self = {
240 + __TYPE__ : MessageType.PLATFORM_CHALLENGE_RESPONSE,
241 + encryptedPlatformChallengeResponse : licenseBinaryBlob(BinaryBlobType.BB_DATA_BLOB),
242 + encryptedHWID : licenseBinaryBlob(BinaryBlobType.BB_DATA_BLOB),
243 + MACData : new type.BinaryString(Buffer.from(Array(16 + 1).join('\x00'), 'binary'), { readLength : new type.CallableValue(16) })
244 + };
245 +
246 + return new type.Component(self, opt);
247 +};
248 +
249 +/**
250 + * Global license packet
251 + * @param packet {type.* | null} send packet
252 + * @returns {type.Component}
253 + */
254 +function licensePacket(message) {
255 + var self = {
256 + bMsgtype : new type.UInt8(function() {
257 + return self.licensingMessage.obj.__TYPE__;
258 + }),
259 + flag : new type.UInt8(Preambule.PREAMBLE_VERSION_3_0),
260 + wMsgSize : new type.UInt16Le(function() {
261 + return new type.Component(self).size();
262 + }),
263 + licensingMessage : message || new type.Factory(function(s) {
264 + switch(self.bMsgtype.value) {
265 + case MessageType.ERROR_ALERT:
266 + self.licensingMessage = licensingErrorMessage({ readLength : new type.CallableValue(function() {
267 + return self.wMsgSize.value - 4;
268 + })}).read(s);
269 + break;
270 + case MessageType.LICENSE_REQUEST:
271 + self.licensingMessage = serverLicenseRequest({ readLength : new type.CallableValue(function() {
272 + return self.wMsgSize.value - 4;
273 + })}).read(s);
274 + break;
275 + case MessageType.NEW_LICENSE_REQUEST:
276 + self.licensingMessage = clientNewLicenseRequest({ readLength : new type.CallableValue(function() {
277 + return self.wMsgSize.value - 4;
278 + })}).read(s);
279 + break;
280 + case MessageType.PLATFORM_CHALLENGE:
281 + self.licensingMessage = serverPlatformChallenge({ readLength : new type.CallableValue(function() {
282 + return self.wMsgSize.value - 4;
283 + })}).read(s);
284 + break;
285 + case MessageType.PLATFORM_CHALLENGE_RESPONSE:
286 + self.licensingMessage = clientPLatformChallengeResponse({ readLength : new type.CallableValue(function() {
287 + return self.wMsgSize.value - 4;
288 + })}).read(s);
289 + break;
290 + default:
291 + log.error('unknown license message type ' + self.bMsgtype.value);
292 + }
293 + })
294 + };
295 +
296 + return new type.Component(self);
297 +}
298 +
299 +/**
300 + * Module exports
301 + */
302 +module.exports = {
303 + MessageType : MessageType,
304 + ErrorCode : ErrorCode,
305 + StateTransition : StateTransition,
306 + licensePacket : licensePacket,
307 + clientNewLicenseRequest : clientNewLicenseRequest,
308 + clientPLatformChallengeResponse : clientPLatformChallengeResponse
309 +};
\ No newline at end of file
rdp/protocol/pdu/sec.js new
+519
@@ -0,0 +1,519 @@
1 +/*
2 + * Copyright (c) 2014-2015 Sylvain Peyrefitte
3 + *
4 + * This file is part of node-rdpjs.
5 + *
6 + * node-rdpjs is free software: you can redistribute it and/or modify
7 + * it under the terms of the GNU General Public License as published by
8 + * the Free Software Foundation, either version 3 of the License, or
9 + * (at your option) any later version.
10 + *
11 + * This program is distributed in the hope that it will be useful,
12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 + * GNU General Public License for more details.
15 + *
16 + * You should have received a copy of the GNU General Public License
17 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 + */
19 +
20 +var inherits = require('util').inherits;
21 +var crypto = require('crypto');
22 +var events = require('events');
23 +var type = require('../../core').type;
24 +var error = require('../../core').error;
25 +var log = require('../../core').log;
26 +var gcc = require('../t125/gcc');
27 +var lic = require('./lic');
28 +var cert = require('../cert');
29 +var rsa = require('../../security').rsa;
30 +
31 +/**
32 + * @see http://msdn.microsoft.com/en-us/library/cc240579.aspx
33 + */
34 +var SecurityFlag = {
35 + SEC_EXCHANGE_PKT : 0x0001,
36 + SEC_TRANSPORT_REQ : 0x0002,
37 + RDP_SEC_TRANSPORT_RSP : 0x0004,
38 + SEC_ENCRYPT : 0x0008,
39 + SEC_RESET_SEQNO : 0x0010,
40 + SEC_IGNORE_SEQNO : 0x0020,
41 + SEC_INFO_PKT : 0x0040,
42 + SEC_LICENSE_PKT : 0x0080,
43 + SEC_LICENSE_ENCRYPT_CS : 0x0200,
44 + SEC_LICENSE_ENCRYPT_SC : 0x0200,
45 + SEC_REDIRECTION_PKT : 0x0400,
46 + SEC_SECURE_CHECKSUM : 0x0800,
47 + SEC_AUTODETECT_REQ : 0x1000,
48 + SEC_AUTODETECT_RSP : 0x2000,
49 + SEC_HEARTBEAT : 0x4000,
50 + SEC_FLAGSHI_VALID : 0x8000
51 +};
52 +
53 +/**
54 + * @see https://msdn.microsoft.com/en-us/library/cc240475.aspx
55 + */
56 +var InfoFlag = {
57 + INFO_MOUSE : 0x00000001,
58 + INFO_DISABLECTRLALTDEL : 0x00000002,
59 + INFO_AUTOLOGON : 0x00000008,
60 + INFO_UNICODE : 0x00000010,
61 + INFO_MAXIMIZESHELL : 0x00000020,
62 + INFO_LOGONNOTIFY : 0x00000040,
63 + INFO_COMPRESSION : 0x00000080,
64 + INFO_ENABLEWINDOWSKEY : 0x00000100,
65 + INFO_REMOTECONSOLEAUDIO : 0x00002000,
66 + INFO_FORCE_ENCRYPTED_CS_PDU : 0x00004000,
67 + INFO_RAIL : 0x00008000,
68 + INFO_LOGONERRORS : 0x00010000,
69 + INFO_MOUSE_HAS_WHEEL : 0x00020000,
70 + INFO_PASSWORD_IS_SC_PIN : 0x00040000,
71 + INFO_NOAUDIOPLAYBACK : 0x00080000,
72 + INFO_USING_SAVED_CREDS : 0x00100000,
73 + INFO_AUDIOCAPTURE : 0x00200000,
74 + INFO_VIDEO_DISABLE : 0x00400000,
75 + INFO_CompressionTypeMask : 0x00001E00
76 +};
77 +
78 +/**
79 + * @see https://msdn.microsoft.com/en-us/library/cc240476.aspx
80 + */
81 +var AfInet = {
82 + AfInet : 0x00002,
83 + AF_INET6 : 0x0017
84 +};
85 +
86 +/**
87 + * @see https://msdn.microsoft.com/en-us/library/cc240476.aspx
88 + */
89 +var PerfFlag = {
90 + PERF_DISABLE_WALLPAPER : 0x00000001,
91 + PERF_DISABLE_FULLWINDOWDRAG : 0x00000002,
92 + PERF_DISABLE_MENUANIMATIONS : 0x00000004,
93 + PERF_DISABLE_THEMING : 0x00000008,
94 + PERF_DISABLE_CURSOR_SHADOW : 0x00000020,
95 + PERF_DISABLE_CURSORSETTINGS : 0x00000040,
96 + PERF_ENABLE_FONT_SMOOTHING : 0x00000080,
97 + PERF_ENABLE_DESKTOP_COMPOSITION : 0x00000100
98 +};
99 +
100 +/**
101 + * @see http://msdn.microsoft.com/en-us/library/cc241992.aspx
102 + * @param input {Buffer} Binary data
103 + * @param salt {Buffer} salt for context call
104 + * @param salt1 {Buffer} another salt (ex : client random)
105 + * @param salt2 {Buffer} another salt (ex : server random)
106 + * @return {Buffer}
107 + */
108 +function saltedHash(input, salt, salt1, salt2) {
109 + var sha1Digest = crypto.createHash('sha1');
110 + sha1Digest.update(input);
111 + sha1Digest.update(salt.slice(0, 48));
112 + sha1Digest.update(salt1);
113 + sha1Digest.update(salt2);
114 +
115 + var sha1Sig = sha1Digest.digest();
116 +
117 + var md5Digest = crypto.createHash('md5');
118 + md5Digest.update(salt.slice(0, 48));
119 + md5Digest.update(sha1Sig);
120 + return md5Digest.digest();
121 +}
122 +
123 +/**
124 + * @param key {Buffer} secret
125 + * @param random1 {Buffer} client random
126 + * @param random2 {Buffer} server random
127 + * @returns {Buffer}
128 + */
129 +function finalHash (key, random1, random2) {
130 + var md5Digest = crypto.createHash('md5');
131 + md5Digest.update(key);
132 + md5Digest.update(random1);
133 + md5Digest.update(random2);
134 + return md5Digest.digest();
135 +}
136 +
137 +/**
138 + * @see http://msdn.microsoft.com/en-us/library/cc241992.aspx
139 + * @param secret {Buffer} secret
140 + * @param random1 {Buffer} client random
141 + * @param random2 {Buffer} server random
142 + * @returns {Buffer}
143 + */
144 +function masterSecret (secret, random1, random2) {
145 + var sh1 = saltedHash(Buffer.from('A'), secret, random1, random2);
146 + var sh2 = saltedHash(Buffer.from('BB'), secret, random1, random2);
147 + var sh3 = saltedHash(Buffer.from('CCC'), secret, random1, random2);
148 +
149 + var ms = Buffer.alloc(sh1.length + sh2.length + sh3.length);
150 + sh1.copy(ms);
151 + sh2.copy(ms, sh1.length);
152 + sh3.copy(ms, sh1.length + sh2.length);
153 + return ms;
154 +}
155 +
156 +/**
157 + * @see http://msdn.microsoft.com/en-us/library/cc241995.aspx
158 + * @param macSaltKey {Buffer} key
159 + * @param data {Buffer} data
160 + * @returns {Buffer}
161 + */
162 +function macData(macSaltKey, data) {
163 + var salt1 = Buffer.alloc(40);
164 + salt1.fill(0x36);
165 +
166 + var salt2 = Buffer.alloc(48);
167 + salt2.fill(0x5c);
168 +
169 + var dataLength = new type.UInt32Le(data.length).toStream().buffer;
170 +
171 + var sha1 = crypto.createHash('sha1');
172 + sha1.update(macSaltKey);
173 + sha1.update(salt1);
174 + sha1.update(dataLength);
175 + sha1.update(data);
176 + var sha1Digest = sha1.digest();
177 +
178 + var md5 = crypto.createHash('md5');
179 + md5.update(macSaltKey);
180 + md5.update(salt2);
181 + md5.update(sha1Digest);
182 +
183 + return md5.digest();
184 +}
185 +
186 +/**
187 + * RDP client informations
188 + * @param extendedInfoConditional {boolean} true if RDP5+
189 + * @returns {type.Component}
190 + */
191 +function rdpInfos(extendedInfoConditional) {
192 + var self = {
193 + codePage : new type.UInt32Le(),
194 + flag : new type.UInt32Le(InfoFlag.INFO_MOUSE | InfoFlag.INFO_UNICODE | InfoFlag.INFO_LOGONNOTIFY | InfoFlag.INFO_LOGONERRORS | InfoFlag.INFO_DISABLECTRLALTDEL | InfoFlag.INFO_ENABLEWINDOWSKEY),
195 + cbDomain : new type.UInt16Le(function() {
196 + return self.domain.size() - 2;
197 + }),
198 + cbUserName : new type.UInt16Le(function() {
199 + return self.userName.size() - 2;
200 + }),
201 + cbPassword : new type.UInt16Le(function() {
202 + return self.password.size() - 2;
203 + }),
204 + cbAlternateShell : new type.UInt16Le(function() {
205 + return self.alternateShell.size() - 2;
206 + }),
207 + cbWorkingDir : new type.UInt16Le(function() {
208 + return self.workingDir.size() - 2;
209 + }),
210 + domain : new type.BinaryString(Buffer.from('\x00', 'ucs2'),{ readLength : new type.CallableValue(function() {
211 + return self.cbDomain.value + 2;
212 + })}),
213 + userName : new type.BinaryString(Buffer.from('\x00', 'ucs2'), { readLength : new type.CallableValue(function() {
214 + return self.cbUserName.value + 2;
215 + })}),
216 + password : new type.BinaryString(Buffer.from('\x00', 'ucs2'), { readLength : new type.CallableValue(function () {
217 + return self.cbPassword.value + 2;
218 + })}),
219 + alternateShell : new type.BinaryString(Buffer.from('\x00', 'ucs2'), { readLength : new type.CallableValue(function() {
220 + return self.cbAlternateShell.value + 2;
221 + })}),
222 + workingDir : new type.BinaryString(Buffer.from('\x00', 'ucs2'), { readLength : new type.CallableValue(function() {
223 + return self.cbWorkingDir.value + 2;
224 + })}),
225 + extendedInfo : rdpExtendedInfos({ conditional : extendedInfoConditional })
226 + };
227 +
228 + return new type.Component(self);
229 +}
230 +
231 +/**
232 + * RDP client extended informations present in RDP5+
233 + * @param opt
234 + * @returns {type.Component}
235 + */
236 +function rdpExtendedInfos(opt) {
237 + var self = {
238 + clientAddressFamily : new type.UInt16Le(AfInet.AfInet),
239 + cbClientAddress : new type.UInt16Le(function() {
240 + return self.clientAddress.size();
241 + }),
242 + clientAddress : new type.BinaryString(Buffer.from('\x00', 'ucs2'),{ readLength : new type.CallableValue(function() {
243 + return self.cbClientAddress;
244 + }) }),
245 + cbClientDir : new type.UInt16Le(function() {
246 + return self.clientDir.size();
247 + }),
248 + clientDir : new type.BinaryString(Buffer.from('\x00', 'ucs2'), { readLength : new type.CallableValue(function() {
249 + return self.cbClientDir;
250 + }) }),
251 + clientTimeZone : new type.BinaryString(Buffer.from(Array(172 + 1).join("\x00"))),
252 + clientSessionId : new type.UInt32Le(),
253 + performanceFlags : new type.UInt32Le()
254 + };
255 + return new type.Component(self, opt);
256 +}
257 +
258 +/**
259 + * Header of security header
260 + * @returns {type.Component}
261 + */
262 +function securityHeader() {
263 + var self = {
264 + securityFlag : new type.UInt16Le(),
265 + securityFlagHi : new type.UInt16Le()
266 + };
267 +
268 + return new type.Component(self);
269 +}
270 +
271 +/**
272 + * Security layer
273 + * @param transport {events.EventEmitter}
274 + */
275 +function Sec(transport, fastPathTransport) {
276 + this.transport = transport;
277 + this.fastPathTransport = fastPathTransport;
278 + // init at connect event from transport layer
279 + this.gccClient = null;
280 + this.gccServer = null;
281 + var self = this;
282 + this.infos = rdpInfos(function() {
283 + return self.gccClient.core.rdpVersion.value === gcc.VERSION.RDP_VERSION_5_PLUS;
284 + });
285 + this.machineName = '';
286 +
287 +
288 + // basic encryption
289 + this.enableEncryption = false;
290 +
291 + if (this.fastPathTransport) {
292 + this.fastPathTransport.on('fastPathData', function (secFlag, s) {
293 + self.recvFastPath(secFlag, s);
294 + });
295 + }
296 +};
297 +
298 +//inherit from Layer
299 +inherits(Sec, events.EventEmitter);
300 +
301 +/**
302 + * Send message with security header
303 + * @param flag {integer} security flag
304 + * @param data {type.*} message
305 + */
306 +Sec.prototype.sendFlagged = function(flag, data) {
307 + this.transport.send('global', new type.Component([
308 + new type.UInt16Le(flag),
309 + new type.UInt16Le(),
310 + data
311 + ]));
312 +};
313 +
314 +/**
315 + * Main send function
316 + * @param message {type.*} message to send
317 + */
318 +Sec.prototype.send = function(message) {
319 + if (this.enableEncryption) {
320 + throw new error.FatalError('NODE_RDP_PROTOCOL_PDU_SEC_ENCRYPT_NOT_IMPLEMENTED');
321 + }
322 + this.transport.send('global', message);
323 +};
324 +
325 +/**
326 + * Main receive function
327 + * @param s {type.Stream}
328 + */
329 +Sec.prototype.recv = function(s) {
330 + if (this.enableEncryption) {
331 + throw new error.FatalError('NODE_RDP_PROTOCOL_PDU_SEC_ENCRYPT_NOT_IMPLEMENTED');
332 + }
333 + // not support yet basic RDP security layer
334 + this.emit('data', s);
335 +};
336 +
337 +/**
338 + * Receive fast path data
339 + * @param secFlag {integer} security flag
340 + * @param s {type.Stream}
341 + */
342 +Sec.prototype.recvFastPath = function (secFlag, s) {
343 + // transparent because basic RDP security layer not implemented
344 + this.emit('fastPathData', secFlag, s);
345 +};
346 +
347 +/**
348 + * Client security layer
349 + * @param transport {events.EventEmitter}
350 + */
351 +function Client(transport, fastPathTransport) {
352 + Sec.call(this, transport, fastPathTransport);
353 + // for basic RDP layer (in futur)
354 + this.enableSecureCheckSum = false;
355 + var self = this;
356 + this.transport.on('connect', function(gccClient, gccServer, userId, channels) {
357 + self.connect(gccClient, gccServer, userId, channels);
358 + }).on('close', function() {
359 + self.emit('close');
360 + }).on('error', function (err) {
361 + self.emit('error', err);
362 + });
363 +};
364 +
365 +//inherit from Layer
366 +inherits(Client, Sec);
367 +
368 +/**
369 + * Connect event
370 + */
371 +Client.prototype.connect = function(gccClient, gccServer, userId, channels) {
372 + //init gcc information
373 + this.gccClient = gccClient;
374 + this.gccServer = gccServer;
375 + this.userId = userId;
376 + this.channelId = channels.find(function(e) {
377 + if(e.name === 'global') return true;
378 + }).id;
379 + this.sendInfoPkt();
380 +};
381 +
382 +/**
383 + * close stack
384 + */
385 +Client.prototype.close = function() {
386 + this.transport.close();
387 +};
388 +
389 +/**
390 + * Send main information packet
391 + * VIP (very important packet) because contain credentials
392 + */
393 +Client.prototype.sendInfoPkt = function() {
394 + this.sendFlagged(SecurityFlag.SEC_INFO_PKT, this.infos);
395 + var self = this;
396 + this.transport.once('global', function(s) {
397 + self.recvLicense(s);
398 + });
399 +};
400 +
401 +function reverse(buffer) {
402 + var result = Buffer.alloc(buffer.length);
403 + for(var i = 0; i < buffer.length; i++) {
404 + result.writeUInt8(buffer.readUInt8(buffer.length - 1 - i), i);
405 + }
406 + return result;
407 +}
408 +
409 +/**
410 + * Send a valid license request
411 + * @param licenseRequest {object(lic.serverLicenseRequest)} license requets infos
412 + */
413 +Client.prototype.sendClientNewLicenseRequest = function(licenseRequest) {
414 + log.debug('new license request');
415 + var serverRandom = licenseRequest.serverRandom.value;
416 +
417 + // read server certificate
418 + var s = new type.Stream(licenseRequest.serverCertificate.obj.blobData.value);
419 + var certificate = cert.certificate().read(s).obj;
420 + var publicKey = certificate.certData.obj.getPublicKey();
421 +
422 + var clientRandom = crypto.randomBytes(32);
423 + var preMasterSecret = crypto.randomBytes(48);
424 + var mSecret = masterSecret(preMasterSecret, clientRandom, serverRandom);
425 + var sessionKeyBlob = masterSecret(mSecret, serverRandom, clientRandom);
426 +
427 + this.licenseMacSalt = sessionKeyBlob.slice(0, 16)
428 + this.licenseKey = finalHash(sessionKeyBlob.slice(16, 32), clientRandom, serverRandom);
429 +
430 + var request = lic.clientNewLicenseRequest();
431 + request.obj.clientRandom.value = clientRandom;
432 +
433 + var preMasterSecretEncrypted = reverse(rsa.encrypt(reverse(preMasterSecret), publicKey));
434 + var preMasterSecretEncryptedPadded = Buffer.alloc(preMasterSecretEncrypted.length + 8);
435 + preMasterSecretEncryptedPadded.fill(0);
436 + preMasterSecretEncrypted.copy(preMasterSecretEncryptedPadded);
437 + request.obj.encryptedPreMasterSecret.obj.blobData.value = preMasterSecretEncryptedPadded;
438 +
439 + request.obj.ClientMachineName.obj.blobData.value = this.infos.obj.userName.value;
440 + request.obj.ClientUserName.obj.blobData.value = Buffer.from(this.machineName + '\x00');
441 +
442 + this.sendFlagged(SecurityFlag.SEC_LICENSE_PKT, lic.licensePacket(request));
443 +};
444 +
445 +/**
446 + * Send a valid license request
447 + * @param platformChallenge {object(lic.serverPlatformChallenge)} platform challenge
448 + */
449 +Client.prototype.sendClientChallengeResponse = function(platformChallenge) {
450 + log.debug('challenge license');
451 + var serverEncryptedChallenge = platformChallenge.encryptedPlatformChallenge.obj.blobData.value;
452 + var serverChallenge = crypto.createDecipheriv('rc4', this.licenseKey, '').update(serverEncryptedChallenge);
453 + if (serverChallenge.toString('ucs2') !== 'TEST\x00') {
454 + throw new error.ProtocolError('NODE_RDP_PROTOCOL_PDU_SEC_INVALID_LICENSE_CHALLENGE');
455 + }
456 +
457 + var hwid = new type.Component([new type.UInt32Le(2), new type.BinaryString(crypto.randomBytes(16))]).toStream().buffer;
458 +
459 + var response = lic.clientPLatformChallengeResponse();
460 + response.obj.encryptedPlatformChallengeResponse.obj.blobData.value = serverEncryptedChallenge;
461 + response.obj.encryptedHWID.obj.blobData.value = crypto.createCipheriv('rc4', this.licenseKey, '').update(hwid);
462 +
463 + var sig = Buffer.alloc(serverChallenge.length + hwid.length);
464 + serverChallenge.copy(sig);
465 + hwid.copy(sig, serverChallenge.length);
466 + response.obj.MACData.value = macData(this.licenseMacSalt, sig);
467 +
468 + this.sendFlagged(SecurityFlag.SEC_LICENSE_PKT, lic.licensePacket(response));
469 +};
470 +
471 +/**
472 + * Receive license informations
473 + * @param s {type.Stream}
474 + */
475 +Sec.prototype.recvLicense = function(s) {
476 + var header = securityHeader().read(s).obj;
477 + if (!(header.securityFlag.value & SecurityFlag.SEC_LICENSE_PKT)) {
478 + throw new error.ProtocolError('NODE_RDP_PROTOCOL_PDU_SEC_BAD_LICENSE_HEADER');
479 + }
480 +
481 + var message = lic.licensePacket().read(s).obj;
482 + // i'm accepted
483 + if (message.bMsgtype.value === lic.MessageType.NEW_LICENSE ||
484 + (message.bMsgtype.value === lic.MessageType.ERROR_ALERT
485 + && message.licensingMessage.obj.dwErrorCode.value === lic.ErrorCode.STATUS_VALID_CLIENT
486 + && message.licensingMessage.obj.dwStateTransition.value === lic.StateTransition.ST_NO_TRANSITION)) {
487 + this.emit('connect', this.gccClient.core, this.userId, this.channelId);
488 + var self = this;
489 + this.transport.on('global', function(s) {
490 + self.recv(s);
491 + });
492 + return;
493 + }
494 +
495 + // server ask license request
496 + if (message.bMsgtype.value === lic.MessageType.LICENSE_REQUEST) {
497 + this.sendClientNewLicenseRequest(message.licensingMessage.obj);
498 + }
499 +
500 + // server send challenge
501 + if (message.bMsgtype.value === lic.MessageType.PLATFORM_CHALLENGE) {
502 + this.sendClientChallengeResponse(message.licensingMessage.obj);
503 + }
504 +
505 + var self = this;
506 + this.emit('connect', this.gccClient.core);
507 + this.transport.once('global', function (s) {
508 + self.recvLicense(s);
509 + });
510 +};
511 +
512 +/**
513 + * Module exports
514 + */
515 +module.exports = {
516 + PerfFlag : PerfFlag,
517 + InfoFlag : InfoFlag,
518 + Client : Client
519 +};
\ No newline at end of file
rdp/protocol/rdp.js new
+361
@@ -0,0 +1,361 @@
1 +/*
2 + * Copyright (c) 2014-2015 Sylvain Peyrefitte
3 + *
4 + * This file is part of node-rdpjs.
5 + *
6 + * node-rdpjs is free software: you can redistribute it and/or modify
7 + * it under the terms of the GNU General Public License as published by
8 + * the Free Software Foundation, either version 3 of the License, or
9 + * (at your option) any later version.
10 + *
11 + * This program is distributed in the hope that it will be useful,
12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 + * GNU General Public License for more details.
15 + *
16 + * You should have received a copy of the GNU General Public License
17 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 + */
19 +
20 +var net = require('net');
21 +var inherits = require('util').inherits;
22 +var events = require('events');
23 +var layer = require('../core').layer;
24 +var error = require('../core').error;
25 +var rle = require('../core').rle;
26 +var log = require('../core').log;
27 +var TPKT = require('./tpkt');
28 +var x224 = require('./x224');
29 +var t125 = require('./t125');
30 +var pdu = require('./pdu');
31 +
32 +/**
33 + * decompress bitmap from RLE algorithm
34 + * @param bitmap {object} bitmap object of bitmap event of node-rdpjs
35 + */
36 +function decompress (bitmap) {
37 + var fName = null;
38 + switch (bitmap.bitsPerPixel.value) {
39 + case 15:
40 + fName = 'bitmap_decompress_15';
41 + break;
42 + case 16:
43 + fName = 'bitmap_decompress_16';
44 + break;
45 + case 24:
46 + fName = 'bitmap_decompress_24';
47 + break;
48 + case 32:
49 + fName = 'bitmap_decompress_32';
50 + break;
51 + default:
52 + throw 'invalid bitmap data format';
53 + }
54 +
55 + var input = new Uint8Array(bitmap.bitmapDataStream.value);
56 + var inputPtr = rle._malloc(input.length);
57 + var inputHeap = new Uint8Array(rle.HEAPU8.buffer, inputPtr, input.length);
58 + inputHeap.set(input);
59 +
60 + var ouputSize = bitmap.width.value * bitmap.height.value * 4;
61 + var outputPtr = rle._malloc(ouputSize);
62 +
63 + var outputHeap = new Uint8Array(rle.HEAPU8.buffer, outputPtr, ouputSize);
64 +
65 + var res = rle.ccall(fName,
66 + 'number',
67 + ['number', 'number', 'number', 'number', 'number', 'number', 'number', 'number'],
68 + [outputHeap.byteOffset, bitmap.width.value, bitmap.height.value, bitmap.width.value, bitmap.height.value, inputHeap.byteOffset, input.length]
69 + );
70 +
71 + var output = new Uint8ClampedArray(outputHeap.buffer, outputHeap.byteOffset, ouputSize);
72 +
73 + rle._free(inputPtr);
74 + rle._free(outputPtr);
75 +
76 + return output;
77 +}
78 +
79 +/**
80 + * Main RDP module
81 + */
82 +function RdpClient(config) {
83 + config = config || {};
84 + this.connected = false;
85 + this.bufferLayer = new layer.BufferLayer(new net.Socket());
86 + this.tpkt = new TPKT(this.bufferLayer);
87 + this.x224 = new x224.Client(this.tpkt, config);
88 + this.mcs = new t125.mcs.Client(this.x224);
89 + this.sec = new pdu.sec.Client(this.mcs, this.tpkt);
90 + this.global = new pdu.global.Client(this.sec, this.sec);
91 +
92 + // config log level
93 + log.level = log.Levels[config.logLevel || 'INFO'] || log.Levels.INFO;
94 +
95 + // credentials
96 + if (config.domain) {
97 + this.sec.infos.obj.domain.value = Buffer.from(config.domain + '\x00', 'ucs2');
98 + }
99 + if (config.userName) {
100 + this.sec.infos.obj.userName.value = Buffer.from(config.userName + '\x00', 'ucs2');
101 + }
102 + if (config.password) {
103 + this.sec.infos.obj.password.value = Buffer.from(config.password + '\x00', 'ucs2');
104 + }
105 + if(config.workingDir) {
106 + this.sec.infos.obj.workingDir.value = Buffer.from(config.workingDir + '\x00', 'ucs2');
107 + }
108 + if(config.alternateShell) {
109 + this.sec.infos.obj.alternateShell.value = Buffer.from(config.alternateShell + '\x00', 'ucs2');
110 + }
111 +
112 + if (config.enablePerf) {
113 + this.sec.infos.obj.extendedInfo.obj.performanceFlags.value =
114 + pdu.sec.PerfFlag.PERF_DISABLE_WALLPAPER
115 + | pdu.sec.PerfFlag.PERF_DISABLE_MENUANIMATIONS
116 + | pdu.sec.PerfFlag.PERF_DISABLE_CURSOR_SHADOW
117 + | pdu.sec.PerfFlag.PERF_DISABLE_THEMING
118 + | pdu.sec.PerfFlag.PERF_DISABLE_FULLWINDOWDRAG;
119 + }
120 +
121 + if (config.autoLogin) {
122 + this.sec.infos.obj.flag.value |= pdu.sec.InfoFlag.INFO_AUTOLOGON;
123 + }
124 +
125 + if (config.screen && config.screen.width && config.screen.height) {
126 + this.mcs.clientCoreData.obj.desktopWidth.value = config.screen.width;
127 + this.mcs.clientCoreData.obj.desktopHeight.value = config.screen.height;
128 + }
129 +
130 + log.debug('screen ' + this.mcs.clientCoreData.obj.desktopWidth.value + 'x' + this.mcs.clientCoreData.obj.desktopHeight.value);
131 +
132 + // config keyboard layout
133 + switch (config.locale) {
134 + case 'fr':
135 + log.debug('french keyboard layout');
136 + this.mcs.clientCoreData.obj.kbdLayout.value = t125.gcc.KeyboardLayout.FRENCH;
137 + break;
138 + case 'en':
139 + default:
140 + log.debug('english keyboard layout');
141 + this.mcs.clientCoreData.obj.kbdLayout.value = t125.gcc.KeyboardLayout.US;
142 + }
143 +
144 +
145 + //bind all events
146 + var self = this;
147 + this.global.on('connect', function () {
148 + self.connected = true;
149 + self.emit('connect');
150 + }).on('session', function () {
151 + self.emit('session');
152 + }).on('close', function () {
153 + self.connected = false;
154 + self.emit('close');
155 + }).on('bitmap', function (bitmaps) {
156 + for(var bitmap in bitmaps) {
157 + var bitmapData = bitmaps[bitmap].obj.bitmapDataStream.value;
158 + var isCompress = bitmaps[bitmap].obj.flags.value & pdu.data.BitmapFlag.BITMAP_COMPRESSION;
159 +
160 + if (isCompress && config.decompress) {
161 + bitmapData = decompress(bitmaps[bitmap].obj);
162 + isCompress = false;
163 + }
164 +
165 + self.emit('bitmap', {
166 + destTop : bitmaps[bitmap].obj.destTop.value,
167 + destLeft : bitmaps[bitmap].obj.destLeft.value,
168 + destBottom : bitmaps[bitmap].obj.destBottom.value,
169 + destRight : bitmaps[bitmap].obj.destRight.value,
170 + width : bitmaps[bitmap].obj.width.value,
171 + height : bitmaps[bitmap].obj.height.value,
172 + bitsPerPixel : bitmaps[bitmap].obj.bitsPerPixel.value,
173 + isCompress : isCompress,
174 + data : bitmapData
175 + });
176 + }
177 + }).on('error', function (err) {
178 + log.warn(err.code + '(' + err.message + ')\n' + err.stack);
179 + if (err instanceof error.FatalError) {
180 + throw err;
181 + }
182 + else {
183 + self.emit('error', err);
184 + }
185 + });
186 +}
187 +
188 +inherits(RdpClient, events.EventEmitter);
189 +
190 +/**
191 + * Connect RDP client
192 + * @param host {string} destination host
193 + * @param port {integer} destination port
194 + */
195 +RdpClient.prototype.connect = function (host, port) {
196 + log.debug('connect to ' + host + ':' + port);
197 + var self = this;
198 + this.bufferLayer.socket.connect(port, host, function () {
199 + // in client mode connection start from x224 layer
200 + self.x224.connect();
201 + });
202 + return this;
203 +};
204 +
205 +/**
206 + * Close RDP client
207 + */
208 +RdpClient.prototype.close = function () {
209 + if(this.connected) {
210 + this.global.close();
211 + }
212 + this.connected = false;
213 + return this;
214 +};
215 +
216 +/**
217 + * Send pointer event to server
218 + * @param x {integer} mouse x position
219 + * @param y {integer} mouse y position
220 + * @param button {integer} button number of mouse
221 + * @param isPressed {boolean} state of button
222 + */
223 +RdpClient.prototype.sendPointerEvent = function (x, y, button, isPressed) {
224 + if (!this.connected)
225 + return;
226 +
227 + var event = pdu.data.pointerEvent();
228 + if (isPressed) {
229 + event.obj.pointerFlags.value |= pdu.data.PointerFlag.PTRFLAGS_DOWN;
230 + }
231 +
232 + switch(button) {
233 + case 1:
234 + event.obj.pointerFlags.value |= pdu.data.PointerFlag.PTRFLAGS_BUTTON1;
235 + break;
236 + case 2:
237 + event.obj.pointerFlags.value |= pdu.data.PointerFlag.PTRFLAGS_BUTTON2;
238 + break;
239 + case 3:
240 + event.obj.pointerFlags.value |= pdu.data.PointerFlag.PTRFLAGS_BUTTON3
241 + break;
242 + default:
243 + event.obj.pointerFlags.value |= pdu.data.PointerFlag.PTRFLAGS_MOVE;
244 + }
245 +
246 + event.obj.xPos.value = x;
247 + event.obj.yPos.value = y;
248 +
249 + this.global.sendInputEvents([event]);
250 +};
251 +
252 +/**
253 + * send scancode event
254 + * @param code {integer}
255 + * @param isPressed {boolean}
256 + * @param extended {boolenan} extended keys
257 + */
258 +RdpClient.prototype.sendKeyEventScancode = function (code, isPressed, extended) {
259 + if (!this.connected)
260 + return;
261 + extended = extended || false;
262 + var event = pdu.data.scancodeKeyEvent();
263 + event.obj.keyCode.value = code;
264 +
265 + if (!isPressed) {
266 + event.obj.keyboardFlags.value |= pdu.data.KeyboardFlag.KBDFLAGS_RELEASE;
267 + }
268 +
269 + if (extended) {
270 + event.obj.keyboardFlags.value |= pdu.data.KeyboardFlag.KBDFLAGS_EXTENDED;
271 + }
272 +
273 + this.global.sendInputEvents([event]);
274 +};
275 +
276 +/**
277 + * Send key event as unicode
278 + * @param code {integer}
279 + * @param isPressed {boolean}
280 + */
281 +RdpClient.prototype.sendKeyEventUnicode = function (code, isPressed) {
282 + if (!this.connected)
283 + return;
284 +
285 + var event = pdu.data.unicodeKeyEvent();
286 + event.obj.unicode.value = code;
287 +
288 + if (!isPressed) {
289 + event.obj.keyboardFlags.value |= pdu.data.KeyboardFlag.KBDFLAGS_RELEASE;
290 + }
291 + this.global.sendInputEvents([event]);
292 +}
293 +
294 +/**
295 + * Wheel mouse event
296 + * @param x {integer} mouse x position
297 + * @param y {integer} mouse y position
298 + * @param step {integer} wheel step
299 + * @param isNegative {boolean}
300 + * @param isHorizontal {boolean}
301 + */
302 +RdpClient.prototype.sendWheelEvent = function (x, y, step, isNegative, isHorizontal) {
303 + if (!this.connected)
304 + return;
305 +
306 + var event = pdu.data.pointerEvent();
307 + if (isHorizontal) {
308 + event.obj.pointerFlags.value |= pdu.data.PointerFlag.PTRFLAGS_HWHEEL;
309 + }
310 + else {
311 + event.obj.pointerFlags.value |= pdu.data.PointerFlag.PTRFLAGS_WHEEL;
312 + }
313 +
314 +
315 + if (isNegative) {
316 + event.obj.pointerFlags.value |= pdu.data.PointerFlag.PTRFLAGS_WHEEL_NEGATIVE;
317 + }
318 +
319 + event.obj.pointerFlags.value |= (step & pdu.data.PointerFlag.WheelRotationMask)
320 +
321 + event.obj.xPos.value = x;
322 + event.obj.yPos.value = y;
323 +
324 + this.global.sendInputEvents([event]);
325 +}
326 +
327 +function createClient(config) {
328 + return new RdpClient(config);
329 +};
330 +
331 +/**
332 + * RDP server side protocol
333 + * @param config {object} configuration
334 + * @param socket {net.Socket}
335 + */
336 +function RdpServer(config, socket) {
337 + if (!(config.key && config.cert)) {
338 + throw new error.FatalError('NODE_RDP_PROTOCOL_RDP_SERVER_CONFIG_MISSING', 'missing cryptographic tools')
339 + }
340 + this.connected = false;
341 + this.bufferLayer = new layer.BufferLayer(socket);
342 + this.tpkt = new TPKT(this.bufferLayer);
343 + this.x224 = new x224.Server(this.tpkt, config.key, config.cert);
344 + this.mcs = new t125.mcs.Server(this.x224);
345 +};
346 +
347 +inherits(RdpServer, events.EventEmitter);
348 +
349 +function createServer (config, next) {
350 + return net.createServer(function (socket) {
351 + next(new RdpServer(config, socket));
352 + });
353 +};
354 +
355 +/**
356 + * Module exports
357 + */
358 +module.exports = {
359 + createClient : createClient,
360 + createServer : createServer
361 +};
\ No newline at end of file
rdp/protocol/t125/gcc.js new
+540
@@ -0,0 +1,540 @@
1 +/*
2 + * Copyright (c) 2014-2015 Sylvain Peyrefitte
3 + *
4 + * This file is part of node-rdpjs.
5 + *
6 + * node-rdpjs is free software: you can redistribute it and/or modify
7 + * it under the terms of the GNU General Public License as published by
8 + * the Free Software Foundation, either version 3 of the License, or
9 + * (at your option) any later version.
10 + *
11 + * This program is distributed in the hope that it will be useful,
12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 + * GNU General Public License for more details.
15 + *
16 + * You should have received a copy of the GNU General Public License
17 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 + */
19 +
20 +var type = require('../../core').type;
21 +var log = require('../../core').log;
22 +var error = require('../../core').error;
23 +var per = require('./per');
24 +
25 +
26 +var t124_02_98_oid = [ 0, 0, 20, 124, 0, 1 ];
27 +var h221_cs_key = "Duca";
28 +var h221_sc_key = "McDn";
29 +
30 +
31 +/**
32 + * @see http://msdn.microsoft.com/en-us/library/cc240509.aspx
33 + */
34 +var MessageType = {
35 + //server -> client
36 + SC_CORE : 0x0C01,
37 + SC_SECURITY : 0x0C02,
38 + SC_NET : 0x0C03,
39 + //client -> server
40 + CS_CORE : 0xC001,
41 + CS_SECURITY : 0xC002,
42 + CS_NET : 0xC003,
43 + CS_CLUSTER : 0xC004,
44 + CS_MONITOR : 0xC005
45 +};
46 +
47 +/**
48 + * @see http://msdn.microsoft.com/en-us/library/cc240510.aspx
49 + */
50 +var ColorDepth = {
51 + RNS_UD_COLOR_8BPP : 0xCA01,
52 + RNS_UD_COLOR_16BPP_555 : 0xCA02,
53 + RNS_UD_COLOR_16BPP_565 : 0xCA03,
54 + RNS_UD_COLOR_24BPP : 0xCA04
55 +};
56 +
57 +/**
58 + * @see http://msdn.microsoft.com/en-us/library/cc240510.aspx
59 + */
60 +var HighColor = {
61 + HIGH_COLOR_4BPP : 0x0004,
62 + HIGH_COLOR_8BPP : 0x0008,
63 + HIGH_COLOR_15BPP : 0x000f,
64 + HIGH_COLOR_16BPP : 0x0010,
65 + HIGH_COLOR_24BPP : 0x0018
66 +};
67 +
68 +/**
69 + * @see http://msdn.microsoft.com/en-us/library/cc240510.aspx
70 + */
71 +var Support = {
72 + RNS_UD_24BPP_SUPPORT : 0x0001,
73 + RNS_UD_16BPP_SUPPORT : 0x0002,
74 + RNS_UD_15BPP_SUPPORT : 0x0004,
75 + RNS_UD_32BPP_SUPPORT : 0x0008
76 +};
77 +
78 +/**
79 + * @see http://msdn.microsoft.com/en-us/library/cc240510.aspx
80 + */
81 +var CapabilityFlag = {
82 + RNS_UD_CS_SUPPORT_ERRINFO_PDU : 0x0001,
83 + RNS_UD_CS_WANT_32BPP_SESSION : 0x0002,
84 + RNS_UD_CS_SUPPORT_STATUSINFO_PDU : 0x0004,
85 + RNS_UD_CS_STRONG_ASYMMETRIC_KEYS : 0x0008,
86 + RNS_UD_CS_UNUSED : 0x0010,
87 + RNS_UD_CS_VALID_CONNECTION_TYPE : 0x0020,
88 + RNS_UD_CS_SUPPORT_MONITOR_LAYOUT_PDU : 0x0040,
89 + RNS_UD_CS_SUPPORT_NETCHAR_AUTODETECT : 0x0080,
90 + RNS_UD_CS_SUPPORT_DYNVC_GFX_PROTOCOL : 0x0100,
91 + RNS_UD_CS_SUPPORT_DYNAMIC_TIME_ZONE : 0x0200,
92 + RNS_UD_CS_SUPPORT_HEARTBEAT_PDU : 0x0400
93 +};
94 +
95 +/**
96 + * @see http://msdn.microsoft.com/en-us/library/cc240510.aspx
97 + */
98 +var ConnectionType = {
99 + CONNECTION_TYPE_MODEM : 0x01,
100 + CONNECTION_TYPE_BROADBAND_LOW : 0x02,
101 + CONNECTION_TYPE_SATELLITE : 0x03,
102 + CONNECTION_TYPE_BROADBAND_HIGH : 0x04,
103 + CONNECTION_TYPE_WAN : 0x05,
104 + CONNECTION_TYPE_LAN : 0x06,
105 + CONNECTION_TYPE_AUTODETECT : 0x07
106 +};
107 +
108 +/**
109 + * @see http://msdn.microsoft.com/en-us/library/cc240510.aspx
110 + */
111 +var VERSION = {
112 + RDP_VERSION_4 : 0x00080001,
113 + RDP_VERSION_5_PLUS : 0x00080004
114 +};
115 +
116 +var Sequence = {
117 + RNS_UD_SAS_DEL : 0xAA03
118 +};
119 +
120 +/**
121 + * @see http://msdn.microsoft.com/en-us/library/cc240511.aspx
122 + */
123 +var EncryptionMethod = {
124 + ENCRYPTION_FLAG_40BIT : 0x00000001,
125 + ENCRYPTION_FLAG_128BIT : 0x00000002,
126 + ENCRYPTION_FLAG_56BIT : 0x00000008,
127 + FIPS_ENCRYPTION_FLAG : 0x00000010
128 +};
129 +
130 +/**
131 + * @see http://msdn.microsoft.com/en-us/library/cc240518.aspx
132 + */
133 +var EncryptionLevel = {
134 + ENCRYPTION_LEVEL_NONE : 0x00000000,
135 + ENCRYPTION_LEVEL_LOW : 0x00000001,
136 + ENCRYPTION_LEVEL_CLIENT_COMPATIBLE : 0x00000002,
137 + ENCRYPTION_LEVEL_HIGH : 0x00000003,
138 + ENCRYPTION_LEVEL_FIPS : 0x00000004
139 +};
140 +
141 +/**
142 + * @see http://msdn.microsoft.com/en-us/library/cc240513.aspx
143 + */
144 +var ChannelOptions = {
145 + CHANNEL_OPTION_INITIALIZED : 0x80000000,
146 + CHANNEL_OPTION_ENCRYPT_RDP : 0x40000000,
147 + CHANNEL_OPTION_ENCRYPT_SC : 0x20000000,
148 + CHANNEL_OPTION_ENCRYPT_CS : 0x10000000,
149 + CHANNEL_OPTION_PRI_HIGH : 0x08000000,
150 + CHANNEL_OPTION_PRI_MED : 0x04000000,
151 + CHANNEL_OPTION_PRI_LOW : 0x02000000,
152 + CHANNEL_OPTION_COMPRESS_RDP : 0x00800000,
153 + CHANNEL_OPTION_COMPRESS : 0x00400000,
154 + CHANNEL_OPTION_SHOW_PROTOCOL : 0x00200000,
155 + REMOTE_CONTROL_PERSISTENT : 0x00100000
156 +};
157 +
158 +/**
159 + * IBM_101_102_KEYS is the most common keyboard type
160 + */
161 +var KeyboardType = {
162 + IBM_PC_XT_83_KEY : 0x00000001,
163 + OLIVETTI : 0x00000002,
164 + IBM_PC_AT_84_KEY : 0x00000003,
165 + IBM_101_102_KEYS : 0x00000004,
166 + NOKIA_1050 : 0x00000005,
167 + NOKIA_9140 : 0x00000006,
168 + JAPANESE : 0x00000007
169 +};
170 +
171 +/**
172 + * @see http://technet.microsoft.com/en-us/library/cc766503%28WS.10%29.aspx
173 + */
174 +var KeyboardLayout = {
175 + ARABIC : 0x00000401,
176 + BULGARIAN : 0x00000402,
177 + CHINESE_US_KEYBOARD : 0x00000404,
178 + CZECH : 0x00000405,
179 + DANISH : 0x00000406,
180 + GERMAN : 0x00000407,
181 + GREEK : 0x00000408,
182 + US : 0x00000409,
183 + SPANISH : 0x0000040a,
184 + FINNISH : 0x0000040b,
185 + FRENCH : 0x0000040c,
186 + HEBREW : 0x0000040d,
187 + HUNGARIAN : 0x0000040e,
188 + ICELANDIC : 0x0000040f,
189 + ITALIAN : 0x00000410,
190 + JAPANESE : 0x00000411,
191 + KOREAN : 0x00000412,
192 + DUTCH : 0x00000413,
193 + NORWEGIAN : 0x00000414
194 +};
195 +
196 +/**
197 + * @see http://msdn.microsoft.com/en-us/library/cc240521.aspx
198 + */
199 +var CertificateType = {
200 + CERT_CHAIN_VERSION_1 : 0x00000001,
201 + CERT_CHAIN_VERSION_2 : 0x00000002
202 +};
203 +
204 +/**
205 + * @param {type.Type} data
206 + * @returns {type.Component}
207 + */
208 +function block(data) {
209 + var self = {
210 + // type of data block
211 + type : new type.UInt16Le(function() {
212 + return self.data.obj.__TYPE__;
213 + }),
214 + // length of entire packet
215 + length : new type.UInt16Le(function() {
216 + return new type.Component(self).size();
217 + }),
218 + // data block
219 + data : data || new type.Factory(function(s){
220 + var options = {
221 + readLength : new type.CallableValue( function () {
222 + return self.length.value - 4;
223 + })
224 + };
225 + switch(self.type.value) {
226 + case MessageType.SC_CORE:
227 + self.data = serverCoreData(options).read(s);
228 + break;
229 + case MessageType.SC_SECURITY:
230 + self.data = serverSecurityData(options).read(s);
231 + break;
232 + case MessageType.SC_NET:
233 + self.data = serverNetworkData(null, options).read(s);
234 + break;
235 + case MessageType.CS_CORE:
236 + self.data = clientCoreData(options).read(s);
237 + break;
238 + case MessageType.CS_SECURITY:
239 + self.data = clientSecurityData(options).read(s);
240 + break;
241 + case MessageType.CS_NET:
242 + self.data = clientNetworkData(null, options).read(s);
243 + break;
244 + default:
245 + log.debug("unknown gcc block type " + self.type.value);
246 + self.data = new type.BinaryString(null, options).read(s);
247 + }
248 + })
249 + };
250 +
251 + return new type.Component(self);
252 +}
253 +
254 +/**
255 + * Main client informations
256 + * keyboard
257 + * screen definition
258 + * color depth
259 + * @see http://msdn.microsoft.com/en-us/library/cc240510.aspx
260 + * @param opt {object} Classic type options
261 + * @returns {type.Component}
262 + */
263 +function clientCoreData(opt) {
264 + var self = {
265 + __TYPE__ : MessageType.CS_CORE,
266 + rdpVersion : new type.UInt32Le(VERSION.RDP_VERSION_5_PLUS),
267 + desktopWidth : new type.UInt16Le(1280),
268 + desktopHeight : new type.UInt16Le(800),
269 + colorDepth : new type.UInt16Le(ColorDepth.RNS_UD_COLOR_8BPP),
270 + sasSequence : new type.UInt16Le(Sequence.RNS_UD_SAS_DEL),
271 + kbdLayout : new type.UInt32Le(KeyboardLayout.FRENCH),
272 + clientBuild : new type.UInt32Le(3790),
273 + clientName : new type.BinaryString(Buffer.from('node-rdpjs\x00\x00\x00\x00\x00\x00', 'ucs2'), { readLength : new type.CallableValue(32) }),
274 + keyboardType : new type.UInt32Le(KeyboardType.IBM_101_102_KEYS),
275 + keyboardSubType : new type.UInt32Le(0),
276 + keyboardFnKeys : new type.UInt32Le(12),
277 + imeFileName : new type.BinaryString(Buffer.from(Array(64 + 1).join('\x00')), { readLength : new type.CallableValue(64), optional : true }),
278 + postBeta2ColorDepth : new type.UInt16Le(ColorDepth.RNS_UD_COLOR_8BPP, { optional : true }),
279 + clientProductId : new type.UInt16Le(1, { optional : true }),
280 + serialNumber : new type.UInt32Le(0, { optional : true }),
281 + highColorDepth : new type.UInt16Le(HighColor.HIGH_COLOR_24BPP, { optional : true }),
282 + supportedColorDepths : new type.UInt16Le(Support.RNS_UD_15BPP_SUPPORT | Support.RNS_UD_16BPP_SUPPORT | Support.RNS_UD_24BPP_SUPPORT | Support.RNS_UD_32BPP_SUPPORT, { optional : true }),
283 + earlyCapabilityFlags : new type.UInt16Le(CapabilityFlag.RNS_UD_CS_SUPPORT_ERRINFO_PDU, { optional : true }),
284 + clientDigProductId : new type.BinaryString(Buffer.from(Array(64 + 1).join('\x00')), { optional : true, readLength : new type.CallableValue(64) }),
285 + connectionType : new type.UInt8(0, { optional : true }),
286 + pad1octet : new type.UInt8(0, { optional : true }),
287 + serverSelectedProtocol : new type.UInt32Le(0, { optional : true })
288 + };
289 +
290 + return new type.Component(self, opt);
291 +}
292 +
293 +/**
294 + * @see http://msdn.microsoft.com/en-us/library/cc240517.aspx
295 + * @param opt {object} Classic type options
296 + * @returns {type.Component}
297 + */
298 +function serverCoreData(opt) {
299 + var self = {
300 + __TYPE__ : MessageType.SC_CORE,
301 + rdpVersion : new type.UInt32Le(VERSION.RDP_VERSION_5_PLUS),
302 + clientRequestedProtocol : new type.UInt32Le(null, { optional : true }),
303 + earlyCapabilityFlags : new type.UInt32Le(null, { optional : true })
304 + };
305 +
306 + return new type.Component(self, opt);
307 +}
308 +
309 +/**
310 + * @see http://msdn.microsoft.com/en-us/library/cc240511.aspx
311 + * @param opt {object} Classic type options
312 + * @returns {type.Component}
313 + */
314 +function clientSecurityData(opt) {
315 + var self = {
316 + __TYPE__ : MessageType.CS_SECURITY,
317 + encryptionMethods : new type.UInt32Le(EncryptionMethod.ENCRYPTION_FLAG_40BIT | EncryptionMethod.ENCRYPTION_FLAG_56BIT | EncryptionMethod.ENCRYPTION_FLAG_128BIT),
318 + extEncryptionMethods : new type.UInt32Le()
319 + };
320 +
321 + return new type.Component(self, opt);
322 +}
323 +
324 +/**
325 + * Only use for SSL (RDP security layer TODO)
326 + * @see http://msdn.microsoft.com/en-us/library/cc240518.aspx
327 + * @param opt {object} Classic type options
328 + * @returns {type.Component}
329 + */
330 +function serverSecurityData(opt) {
331 + var self = {
332 + __TYPE__ : MessageType.SC_SECURITY,
333 + encryptionMethod : new type.UInt32Le(),
334 + encryptionLevel : new type.UInt32Le()
335 + };
336 +
337 + return new type.Component(self, opt);
338 +}
339 +
340 +/**
341 + * Channel definition
342 + * @param opt {object} Classic type options
343 + * @returns {type.Component}
344 + */
345 +function channelDef (opt) {
346 + var self = {
347 + name : new type.BinaryString(null, { readLength : new type.CallableValue(8) }),
348 + options : new type.UInt32Le()
349 + };
350 +
351 + return new type.Component(self, opt);
352 +}
353 +
354 +/**
355 + * Optional channel requests (sound, clipboard ...)
356 + * @param opt {object} Classic type options
357 + * @returns {type.Component}
358 + */
359 +function clientNetworkData(channelDefArray, opt) {
360 + var self = {
361 + __TYPE__ : MessageType.CS_NET,
362 + channelCount : new type.UInt32Le( function () {
363 + return self.channelDefArray.obj.length;
364 + }),
365 + channelDefArray : channelDefArray || new type.Factory( function (s) {
366 + self.channelDefArray = new type.Component([]);
367 +
368 + for (var i = 0; i < self.channelCount.value; i++) {
369 + self.channelDefArray.obj.push(channelDef().read(s));
370 + }
371 + })
372 + };
373 +
374 + return new type.Component(self, opt);
375 +}
376 +
377 +/**
378 + * @param channelIds {type.Component} list of available channels
379 + * @param opt {object} Classic type options
380 + * @returns {type.Component}
381 + */
382 +function serverNetworkData (channelIds, opt) {
383 + var self = {
384 + __TYPE__ : MessageType.SC_NET,
385 + MCSChannelId : new type.UInt16Le(1003, { constant : true }),
386 + channelCount : new type.UInt16Le(function () {
387 + return self.channelIdArray.obj.length;
388 + }),
389 + channelIdArray : channelIds || new type.Factory( function (s) {
390 + self.channelIdArray = new type.Component([]);
391 + for (var i = 0; i < self.channelCount.value; i++) {
392 + self.channelIdArray.obj.push(new type.UInt16Le().read(s));
393 + }
394 + }),
395 + pad : new type.UInt16Le(null, { conditional : function () {
396 + return (self.channelCount.value % 2) === 1;
397 + }})
398 + };
399 +
400 + return new type.Component(self, opt);
401 +}
402 +
403 +/**
404 + * Client or server GCC settings block
405 + * @param blocks {type.Component} array of gcc blocks
406 + * @param opt {object} options to component type
407 + * @returns {type.Component}
408 + */
409 +function settings(blocks, opt) {
410 + var self = {
411 + blocks : blocks || new type.Factory(function(s) {
412 + self.blocks = new type.Component([]);
413 + // read until end of stream
414 + while(s.availableLength() > 0) {
415 + self.blocks.obj.push(block().read(s));
416 + }
417 + }),
418 + };
419 +
420 + return new type.Component(self, opt);
421 +}
422 +
423 +/**
424 + * Read GCC response from server
425 + * @param s {type.Stream} current stream
426 + * @returns {Array(type.Component)} list of server block
427 + */
428 +function readConferenceCreateResponse(s) {
429 + per.readChoice(s);
430 +
431 + if(!per.readObjectIdentifier(s, t124_02_98_oid)) {
432 + throw new error.ProtocolError('NODE_RDP_PROTOCOL_T125_GCC_BAD_OBJECT_IDENTIFIER_T124');
433 + }
434 +
435 + per.readLength(s);
436 + per.readChoice(s);
437 + per.readInteger16(s, 1001);
438 + per.readInteger(s);
439 + per.readEnumerates(s);
440 + per.readNumberOfSet(s);
441 + per.readChoice(s);
442 +
443 + if (!per.readOctetStream(s, h221_sc_key, 4)) {
444 + throw new error.ProtocolError('NODE_RDP_PROTOCOL_T125_GCC_BAD_H221_SC_KEY');
445 + }
446 +
447 + length = per.readLength(s);
448 + serverSettings = settings(null, { readLength : new type.CallableValue(length) });
449 +
450 + // Object magic
451 + return serverSettings.read(s).obj.blocks.obj.map(function(e) {
452 + return e.obj.data;
453 + });
454 +}
455 +
456 +/**
457 + * Read GCC request
458 + * @param s {type.Stream}
459 + * @returns {Array(type.Component)} list of client block
460 + */
461 +function readConferenceCreateRequest (s) {
462 + per.readChoice(s);
463 + if (!per.readObjectIdentifier(s, t124_02_98_oid)) {
464 + throw new error.ProtocolError('NODE_RDP_PROTOCOL_T125_GCC_BAD_H221_SC_KEY');
465 + }
466 + per.readLength(s);
467 + per.readChoice(s);
468 + per.readSelection(s);
469 + per.readNumericString(s, 1);
470 + per.readPadding(s, 1);
471 +
472 + if (per.readNumberOfSet(s) !== 1) {
473 + throw new error.ProtocolError('NODE_RDP_PROTOCOL_T125_GCC_BAD_SET');
474 + }
475 +
476 + if (per.readChoice(s) !== 0xc0) {
477 + throw new error.ProtocolError('NODE_RDP_PROTOCOL_T125_GCC_BAD_CHOICE');
478 + }
479 +
480 + per.readOctetStream(s, h221_cs_key, 4);
481 +
482 + length = per.readLength(s);
483 + var clientSettings = settings(null, { readLength : new type.CallableValue(length) });
484 +
485 + // Object magic
486 + return clientSettings.read(s).obj.blocks.obj.map(function(e) {
487 + return e.obj.data;
488 + });
489 +}
490 +
491 +/**
492 + * Built {type.Componen} from gcc user data
493 + * @param userData {type.Component} GCC data from client
494 + * @returns {type.Component} GCC encoded client user data
495 + */
496 +function writeConferenceCreateRequest (userData) {
497 + var userDataStream = new type.Stream(userData.size());
498 + userData.write(userDataStream);
499 +
500 + return new type.Component([
501 + per.writeChoice(0), per.writeObjectIdentifier(t124_02_98_oid),
502 + per.writeLength(userData.size() + 14), per.writeChoice(0),
503 + per.writeSelection(0x08), per.writeNumericString("1", 1), per.writePadding(1),
504 + per.writeNumberOfSet(1), per.writeChoice(0xc0),
505 + per.writeOctetStream(Buffer.from(h221_cs_key), 4), per.writeOctetStream(userDataStream.getValue())
506 + ]);
507 +}
508 +
509 +function writeConferenceCreateResponse (userData) {
510 + var userDataStream = new type.Stream(userData.size());
511 + userData.write(userDataStream);
512 +
513 + return new type.Component([
514 + per.writeChoice(0), per.writeObjectIdentifier(t124_02_98_oid),
515 + per.writeLength(userData.size() + 14), per.writeChoice(0x14),
516 + per.writeInteger16(0x79F3, 1001), per.writeInteger(1), per.writeEnumerates(0),
517 + per.writeNumberOfSet(1), per.writeChoice(0xc0),
518 + per.writeOctetStream(Buffer.from(h221_sc_key), 4), per.writeOctetStream(userDataStream.getValue())
519 + ]);
520 +}
521 +
522 +/**
523 + * Module exports
524 + */
525 +module.exports = {
526 + MessageType : MessageType,
527 + VERSION : VERSION,
528 + KeyboardLayout : KeyboardLayout,
529 + block : block,
530 + clientCoreData : clientCoreData,
531 + clientNetworkData : clientNetworkData,
532 + clientSecurityData : clientSecurityData,
533 + serverCoreData : serverCoreData,
534 + serverSecurityData : serverSecurityData,
535 + serverNetworkData : serverNetworkData,
536 + readConferenceCreateResponse : readConferenceCreateResponse,
537 + readConferenceCreateRequest : readConferenceCreateRequest,
538 + writeConferenceCreateRequest : writeConferenceCreateRequest,
539 + writeConferenceCreateResponse : writeConferenceCreateResponse
540 +};
\ No newline at end of file
rdp/protocol/t125/index.js new
+26
@@ -0,0 +1,26 @@
1 +/*
2 + * Copyright (c) 2014-2015 Sylvain Peyrefitte
3 + *
4 + * This file is part of node-rdpjs.
5 + *
6 + * node-rdpjs is free software: you can redistribute it and/or modify
7 + * it under the terms of the GNU General Public License as published by
8 + * the Free Software Foundation, either version 3 of the License, or
9 + * (at your option) any later version.
10 + *
11 + * This program is distributed in the hope that it will be useful,
12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 + * GNU General Public License for more details.
15 + *
16 + * You should have received a copy of the GNU General Public License
17 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 + */
19 +
20 +var mcs = require('./mcs');
21 +var gcc = require('./gcc');
22 +
23 +module.exports = {
24 + mcs : mcs,
25 + gcc : gcc
26 +};
rdp/protocol/t125/mcs.js new
+490
@@ -0,0 +1,490 @@
1 +/*
2 + * Copyright (c) 2014-2015 Sylvain Peyrefitte
3 + *
4 + * This file is part of node-rdpjs.
5 + *
6 + * node-rdpjs is free software: you can redistribute it and/or modify
7 + * it under the terms of the GNU General Public License as published by
8 + * the Free Software Foundation, either version 3 of the License, or
9 + * (at your option) any later version.
10 + *
11 + * This program is distributed in the hope that it will be useful,
12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 + * GNU General Public License for more details.
15 + *
16 + * You should have received a copy of the GNU General Public License
17 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 + */
19 +
20 +var inherits = require('util').inherits;
21 +var events = require('events');
22 +var type = require('../../core').type;
23 +var log = require('../../core').log;
24 +var error = require('../../core').error;
25 +var gcc = require('./gcc');
26 +var per = require('./per');
27 +var asn1 = require('../../asn1');
28 +
29 +var Message = {
30 + MCS_TYPE_CONNECT_INITIAL : 0x65,
31 + MCS_TYPE_CONNECT_RESPONSE : 0x66
32 +};
33 +
34 +var DomainMCSPDU = {
35 + ERECT_DOMAIN_REQUEST : 1,
36 + DISCONNECT_PROVIDER_ULTIMATUM : 8,
37 + ATTACH_USER_REQUEST : 10,
38 + ATTACH_USER_CONFIRM : 11,
39 + CHANNEL_JOIN_REQUEST : 14,
40 + CHANNEL_JOIN_CONFIRM : 15,
41 + SEND_DATA_REQUEST : 25,
42 + SEND_DATA_INDICATION : 26
43 +};
44 +
45 +var Channel = {
46 + MCS_GLOBAL_CHANNEL : 1003,
47 + MCS_USERCHANNEL_BASE : 1001
48 +};
49 +
50 +/**
51 + * @see http://www.itu.int/rec/T-REC-T.125-199802-I/en page 25
52 + * @returns {asn1.univ.Sequence}
53 + */
54 +function DomainParameters(maxChannelIds, maxUserIds, maxTokenIds,
55 + numPriorities, minThoughput, maxHeight, maxMCSPDUsize, protocolVersion) {
56 + return new asn1.univ.Sequence({
57 + maxChannelIds : new asn1.univ.Integer(maxChannelIds),
58 + maxUserIds : new asn1.univ.Integer(maxUserIds),
59 + maxTokenIds : new asn1.univ.Integer(maxTokenIds),
60 + numPriorities : new asn1.univ.Integer(numPriorities),
61 + minThoughput : new asn1.univ.Integer(minThoughput),
62 + maxHeight : new asn1.univ.Integer(maxHeight),
63 + maxMCSPDUsize : new asn1.univ.Integer(maxMCSPDUsize),
64 + protocolVersion : new asn1.univ.Integer(protocolVersion)
65 + });
66 +}
67 +
68 +/**
69 + * @see http://www.itu.int/rec/T-REC-T.125-199802-I/en page 25
70 + * @param userData {Buffer}
71 + * @returns {asn1.univ.Sequence}
72 + */
73 +function ConnectInitial (userData) {
74 + return new asn1.univ.Sequence({
75 + callingDomainSelector : new asn1.univ.OctetString(Buffer.from('\x01', 'binary')),
76 + calledDomainSelector : new asn1.univ.OctetString(Buffer.from('\x01', 'binary')),
77 + upwardFlag : new asn1.univ.Boolean(true),
78 + targetParameters : DomainParameters(34, 2, 0, 1, 0, 1, 0xffff, 2),
79 + minimumParameters : DomainParameters(1, 1, 1, 1, 0, 1, 0x420, 2),
80 + maximumParameters : DomainParameters(0xffff, 0xfc17, 0xffff, 1, 0, 1, 0xffff, 2),
81 + userData : new asn1.univ.OctetString(userData)
82 + }).implicitTag(new asn1.spec.Asn1Tag(asn1.spec.TagClass.Application, asn1.spec.TagFormat.Constructed, 101));
83 +}
84 +
85 +/**
86 + * @see http://www.itu.int/rec/T-REC-T.125-199802-I/en page 25
87 + * @returns {asn1.univ.Sequence}
88 + */
89 +function ConnectResponse (userData) {
90 + return new asn1.univ.Sequence({
91 + result : new asn1.univ.Enumerate(0),
92 + calledConnectId : new asn1.univ.Integer(0),
93 + domainParameters : DomainParameters(22, 3, 0, 1, 0, 1,0xfff8, 2),
94 + userData : new asn1.univ.OctetString(userData)
95 + }).implicitTag(new asn1.spec.Asn1Tag(asn1.spec.TagClass.Application, asn1.spec.TagFormat.Constructed, 102));
96 +}
97 +
98 +/**
99 + * Format MCS PDU header packet
100 + * @param mcsPdu {integer}
101 + * @param options {integer}
102 + * @returns {type.UInt8} headers
103 + */
104 +function writeMCSPDUHeader(mcsPdu, options) {
105 + options = options || 0;
106 + return new type.UInt8((mcsPdu << 2) | options);
107 +}
108 +
109 +/**
110 + * Read MCS PDU header
111 + * @param opcode
112 + * @param mcsPdu
113 + * @returns {Boolean}
114 + */
115 +function readMCSPDUHeader(opcode, mcsPdu) {
116 + return (opcode >> 2) === mcsPdu;
117 +}
118 +
119 +/**
120 + * Multi-Channel Services
121 + * @param transport {events.EventEmitter} transport layer listen (connect, data) events
122 + * @param recvOpCode {DomainMCSPDU} opcode use in receive automata
123 + * @param sendOpCode {DomainMCSPDU} opcode use to send message
124 + */
125 +function MCS(transport, recvOpCode, sendOpCode) {
126 + this.transport = transport;
127 + this.recvOpCode = recvOpCode;
128 + this.sendOpCode = sendOpCode;
129 + this.channels = [{id : Channel.MCS_GLOBAL_CHANNEL, name : 'global'}];
130 + this.channels.find = function(callback) {
131 + for(var i in this) {
132 + if(callback(this[i])) return this[i];
133 + };
134 + };
135 +
136 + // bind events
137 + var self = this;
138 + this.transport.on('close', function () {
139 + self.emit('close');
140 + }).on('error', function (err) {
141 + self.emit('error', err);
142 + });
143 +}
144 +
145 +//inherit from Layer
146 +inherits(MCS, events.EventEmitter);
147 +
148 +/**
149 + * Send message to a specific channel
150 + * @param channelName {string} name of channel
151 + * @param data {type.*} message to send
152 + */
153 +MCS.prototype.send = function(channelName, data) {
154 + var channelId = this.channels.find(function(element) {
155 + if (element.name === channelName) return true;
156 + }).id;
157 +
158 + this.transport.send(new type.Component([
159 + writeMCSPDUHeader(this.sendOpCode),
160 + per.writeInteger16(this.userId, Channel.MCS_USERCHANNEL_BASE),
161 + per.writeInteger16(channelId),
162 + new type.UInt8(0x70),
163 + per.writeLength(data.size()),
164 + data
165 + ]));
166 +};
167 +
168 +/**
169 + * Main receive function
170 + * @param s {type.Stream}
171 + */
172 +MCS.prototype.recv = function(s) {
173 + opcode = new type.UInt8().read(s).value;
174 +
175 + if (readMCSPDUHeader(opcode, DomainMCSPDU.DISCONNECT_PROVIDER_ULTIMATUM)) {
176 + log.info("MCS DISCONNECT_PROVIDER_ULTIMATUM");
177 + this.transport.close();
178 + return
179 + }
180 + else if(!readMCSPDUHeader(opcode, this.recvOpCode)) {
181 + throw new error.UnexpectedFatalError('NODE_RDP_PROTOCOL_T125_MCS_BAD_RECEIVE_OPCODE');
182 + }
183 +
184 + per.readInteger16(s, Channel.MCS_USERCHANNEL_BASE);
185 +
186 + var channelId = per.readInteger16(s);
187 +
188 + per.readEnumerates(s);
189 + per.readLength(s);
190 +
191 + var channelName = this.channels.find(function(e) {
192 + if (e.id === channelId) return true;
193 + }).name;
194 +
195 + this.emit(channelName, s);
196 +};
197 +
198 +/**
199 + * Only main channels handle actually
200 + * @param transport {event.EventEmitter} bind connect and data events
201 + * @returns
202 + */
203 +function Client(transport) {
204 + MCS.call(this, transport, DomainMCSPDU.SEND_DATA_INDICATION, DomainMCSPDU.SEND_DATA_REQUEST);
205 +
206 + // channel context automata
207 + this.channelsConnected = 0;
208 +
209 + // init gcc information
210 + this.clientCoreData = gcc.clientCoreData();
211 + this.clientNetworkData = gcc.clientNetworkData(new type.Component([]));
212 + this.clientSecurityData = gcc.clientSecurityData();
213 +
214 + // must be readed from protocol
215 + this.serverCoreData = null;
216 + this.serverSecurityData = null;
217 + this.serverNetworkData = null;
218 +
219 + var self = this;
220 + this.transport.on('connect', function(s) {
221 + self.connect(s);
222 + });
223 +}
224 +
225 +inherits(Client, MCS);
226 +
227 +/**
228 + * Connect event layer
229 + */
230 +Client.prototype.connect = function(selectedProtocol) {
231 + this.clientCoreData.obj.serverSelectedProtocol.value = selectedProtocol;
232 + this.sendConnectInitial();
233 +};
234 +
235 +/**
236 + * close stack
237 + */
238 +Client.prototype.close = function() {
239 + this.transport.close();
240 +};
241 +
242 +/**
243 + * MCS connect response (server->client)
244 + * @param s {type.Stream}
245 + */
246 +Client.prototype.recvConnectResponse = function(s) {
247 + var userData = new type.Stream(ConnectResponse().decode(s, asn1.ber).value.userData.value);
248 + var serverSettings = gcc.readConferenceCreateResponse(userData);
249 + // record server gcc block
250 + for(var i in serverSettings) {
251 + if(!serverSettings[i].obj) {
252 + continue;
253 + }
254 + switch(serverSettings[i].obj.__TYPE__) {
255 + case gcc.MessageType.SC_CORE:
256 + this.serverCoreData = serverSettings[i];
257 + break;
258 + case gcc.MessageType.SC_SECURITY:
259 + this.serverSecurityData = serverSettings[i];
260 + break;
261 + case gcc.MessageType.SC_NET:
262 + this.serverNetworkData = serverSettings[i];
263 + break;
264 + default:
265 + log.warn('unhandle server gcc block : ' + serverSettings[i].obj.__TYPE__);
266 + }
267 + }
268 +
269 + // send domain request
270 + this.sendErectDomainRequest();
271 + // send attach user request
272 + this.sendAttachUserRequest();
273 + // now wait user confirm from server
274 + var self = this;
275 + this.transport.once('data', function(s) {
276 + self.recvAttachUserConfirm(s);
277 + });
278 +};
279 +
280 +/**
281 + * MCS connection automata step
282 + * @param s {type.Stream}
283 + */
284 +Client.prototype.recvAttachUserConfirm = function(s) {
285 + if (!readMCSPDUHeader(new type.UInt8().read(s).value, DomainMCSPDU.ATTACH_USER_CONFIRM)) {
286 + throw new error.UnexpectedFatalError('NODE_RDP_PROTOCOL_T125_MCS_BAD_HEADER');
287 + }
288 +
289 + if (per.readEnumerates(s) !== 0) {
290 + throw new error.UnexpectedFatalError('NODE_RDP_PROTOCOL_T125_MCS_SERVER_REJECT_USER');
291 + }
292 +
293 + this.userId = per.readInteger16(s, Channel.MCS_USERCHANNEL_BASE);
294 + //ask channel for specific user
295 + this.channels.push({ id : this.userId, name : 'user' });
296 + // channel connect automata
297 + this.connectChannels();
298 +};
299 +
300 +/**
301 + * Last state in channel connection automata
302 + * @param s {type.Stream}
303 + */
304 +Client.prototype.recvChannelJoinConfirm = function(s) {
305 + var opcode = new type.UInt8().read(s).value;
306 +
307 + if (!readMCSPDUHeader(opcode, DomainMCSPDU.CHANNEL_JOIN_CONFIRM)) {
308 + throw new error.UnexpectedFatalError('NODE_RDP_PROTOCOL_T125_MCS_WAIT_CHANNEL_JOIN_CONFIRM');
309 + }
310 +
311 + var confirm = per.readEnumerates(s);
312 +
313 + var userId = per.readInteger16(s, Channel.MCS_USERCHANNEL_BASE);
314 + if (this.userId !== userId) {
315 + throw new error.UnexpectedFatalError('NODE_RDP_PROTOCOL_T125_MCS_INVALID_USER_ID');
316 + }
317 +
318 + var channelId = per.readInteger16(s);
319 +
320 + if ((confirm !== 0) && (channelId === Channel.MCS_GLOBAL_CHANNEL || channelId === this.userId)) {
321 + throw new error.UnexpectedFatalError('NODE_RDP_PROTOCOL_T125_MCS_SERVER_MUST_CONFIRM_STATIC_CHANNEL');
322 + }
323 +
324 + this.connectChannels();
325 +};
326 +
327 +/**
328 + * First MCS message
329 + */
330 +Client.prototype.sendConnectInitial = function() {
331 +
332 + var ccReq = gcc.writeConferenceCreateRequest(new type.Component([
333 + gcc.block(this.clientCoreData),
334 + gcc.block(this.clientNetworkData),
335 + gcc.block(this.clientSecurityData)
336 + ])).toStream().getValue();
337 +
338 + this.transport.send(ConnectInitial(ccReq).encode(asn1.ber));
339 +
340 + // next event is connect response
341 + var self = this;
342 + this.transport.once('data', function(s) {
343 + self.recvConnectResponse(s);
344 + });
345 +};
346 +
347 +/**
348 + * MCS connection automata step
349 + */
350 +Client.prototype.sendErectDomainRequest = function() {
351 + this.transport.send(new type.Component([
352 + writeMCSPDUHeader(DomainMCSPDU.ERECT_DOMAIN_REQUEST),
353 + per.writeInteger(0),
354 + per.writeInteger(0)
355 + ]));
356 +};
357 +
358 +/**
359 + * MCS connection automata step
360 + */
361 +Client.prototype.sendAttachUserRequest = function() {
362 + this.transport.send(writeMCSPDUHeader(DomainMCSPDU.ATTACH_USER_REQUEST));
363 +};
364 +
365 +/**
366 + * Send a channel join request
367 + * @param channelId {integer} channel id
368 + */
369 +Client.prototype.sendChannelJoinRequest = function(channelId) {
370 + this.transport.send(new type.Component([
371 + writeMCSPDUHeader(DomainMCSPDU.CHANNEL_JOIN_REQUEST),
372 + per.writeInteger16(this.userId, Channel.MCS_USERCHANNEL_BASE),
373 + per.writeInteger16(channelId)
374 + ]));
375 +};
376 +
377 +/**
378 + * Connect channels automata
379 + * @param s {type.Stream}
380 + */
381 +Client.prototype.connectChannels = function(s) {
382 + if(this.channelsConnected == this.channels.length) {
383 + var self = this;
384 + this.transport.on('data', function(s) {
385 + self.recv(s);
386 + });
387 +
388 + // send client and sever gcc informations
389 + this.emit('connect',
390 + {
391 + core : this.clientCoreData.obj,
392 + security : this.clientSecurityData.obj,
393 + net : this.clientNetworkData.obj
394 + },
395 + {
396 + core : this.serverCoreData.obj,
397 + security : this.serverSecurityData.obj
398 + }, this.userId, this.channels);
399 + return;
400 + }
401 +
402 + this.sendChannelJoinRequest(this.channels[this.channelsConnected++].id);
403 +
404 + var self = this;
405 + this.transport.once('data', function(s) {
406 + self.recvChannelJoinConfirm(s);
407 + });
408 +};
409 +
410 +/**
411 + * Server side of MCS layer
412 + * @param transport
413 + */
414 +function Server (transport) {
415 + MCS.call(this, transport, DomainMCSPDU.SEND_DATA_REQUEST, DomainMCSPDU.SEND_DATA_INDICATION);
416 +
417 + // must be readed from protocol
418 + this.clientCoreData = null;
419 + this.clientNetworkData = null;
420 + this.clientSecurityData = null;
421 +
422 + // init gcc information
423 + this.serverCoreData = gcc.serverCoreData();
424 + this.serverSecurityData = gcc.serverSecurityData();
425 + this.serverNetworkData = gcc.serverNetworkData(new type.Component([]));
426 +
427 + var self = this;
428 + this.transport.on('connect', function (selectedProtocol) {
429 + self.serverCoreData.obj.clientRequestedProtocol.value = selectedProtocol;
430 + }).once('data', function (s) {
431 + self.recvConnectInitial(s);
432 + });
433 +}
434 +
435 +inherits(Server, MCS);
436 +
437 +/**
438 + * First state of server automata
439 + * @param s {type.Stream}
440 + */
441 +Server.prototype.recvConnectInitial = function (s) {
442 + var userData = new type.Stream(ConnectInitial().decode(s, asn1.ber).value.userData.value);
443 + var clientSettings = gcc.readConferenceCreateRequest(userData);
444 + // record server gcc block
445 + for(var i in clientSettings) {
446 + if(!clientSettings[i].obj) {
447 + continue;
448 + }
449 + switch(clientSettings[i].obj.__TYPE__) {
450 + case gcc.MessageType.CS_CORE:
451 + this.clientCoreData = clientSettings[i];
452 + break;
453 + case gcc.MessageType.CS_SECURITY:
454 + this.clientSecurityData = clientSettings[i];
455 + break;
456 + case gcc.MessageType.CS_NET:
457 + this.clientNetworkData = clientSettings[i];
458 + for (var i = 0; i < this.clientNetworkData.obj.channelCount.value; i++) {
459 + this.serverNetworkData.obj.channelIdArray.obj.push(new type.UInt16Le( i + 1 + Channel.MCS_GLOBAL_CHANNEL));
460 + }
461 + break;
462 + default:
463 + log.debug('unhandle client gcc block : ' + clientSettings[i].obj.__TYPE__);
464 + }
465 + }
466 +
467 + this.sendConnectResponse();
468 +};
469 +
470 +/**
471 + * State 2 in mcs server connetion automata
472 + */
473 +Server.prototype.sendConnectResponse = function () {
474 + var ccReq = gcc.writeConferenceCreateResponse(new type.Component([
475 + gcc.block(this.serverCoreData),
476 + gcc.block(this.serverSecurityData),
477 + gcc.block(this.serverNetworkData),
478 + ])).toStream().getValue();
479 +
480 + this.transport.send(ConnectResponse(ccReq).encode(asn1.ber));
481 +
482 +};
483 +
484 +/**
485 + * Module exports
486 + */
487 +module.exports = {
488 + Client : Client,
489 + Server : Server
490 +};
rdp/protocol/t125/per.js new
+338
@@ -0,0 +1,338 @@
1 +/*
2 + * Copyright (c) 2014-2015 Sylvain Peyrefitte
3 + *
4 + * This file is part of node-rdpjs.
5 + *
6 + * node-rdpjs is free software: you can redistribute it and/or modify
7 + * it under the terms of the GNU General Public License as published by
8 + * the Free Software Foundation, either version 3 of the License, or
9 + * (at your option) any later version.
10 + *
11 + * This program is distributed in the hope that it will be useful,
12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 + * GNU General Public License for more details.
15 + *
16 + * You should have received a copy of the GNU General Public License
17 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 + */
19 +
20 +var type = require('../../core').type;
21 +var error = require('../../core').error;
22 +
23 +/**
24 + * @param s {type.Stream} read value from stream
25 + * @returns read length from per format
26 + */
27 +function readLength(s) {
28 + var byte = new type.UInt8().read(s).value;
29 + var size = 0;
30 + if(byte & 0x80) {
31 + byte &= ~0x80;
32 + size = byte << 8;
33 + size += new type.UInt8().read(s).value;
34 + }
35 + else {
36 + size = byte;
37 + }
38 + return size;
39 +}
40 +
41 +/**
42 + * @param value {raw} value to convert to per format
43 + * @returns type objects per encoding value
44 + */
45 +function writeLength(value) {
46 + if(value > 0x7f) {
47 + return new type.UInt16Be(value | 0x8000);
48 + }
49 + else {
50 + return new type.UInt8(value);
51 + }
52 +}
53 +
54 +/**
55 + * @param s {type.Stream}
56 + * @returns {integer} choice decoding from per encoding
57 + */
58 +function readChoice(s) {
59 + return new type.UInt8().read(s).value;
60 +}
61 +
62 +/**
63 + * @param choice {integer}
64 + * @returns {type.UInt8} choice per encoded
65 + */
66 +function writeChoice(choice) {
67 + return new type.UInt8(choice);
68 +}
69 +
70 +/**
71 + * @param s {type.Stream}
72 + * @returns {integer} number represent selection
73 + */
74 +function readSelection(s) {
75 + return new type.UInt8().read(s).value;
76 +}
77 +
78 +/**
79 + * @param selection {integer}
80 + * @returns {type.UInt8} per encoded selection
81 + */
82 +function writeSelection(selection) {
83 + return new type.UInt8(selection);
84 +}
85 +
86 +/**
87 + * @param s {type.Stream}
88 + * @returns {integer} number of sets
89 + */
90 +function readNumberOfSet(s) {
91 + return new type.UInt8().read(s).value;
92 +}
93 +
94 +/**
95 + * @param numberOfSet {integer}
96 + * @returns {type.UInt8} per encoded nuimber of sets
97 + */
98 +function writeNumberOfSet(numberOfSet) {
99 + return new type.UInt8(numberOfSet);
100 +}
101 +
102 +/**
103 + * @param s {type.Stream}
104 + * @returns {integer} enumerates number
105 + */
106 +function readEnumerates(s) {
107 + return new type.UInt8().read(s).value;
108 +}
109 +
110 +/**
111 + * @param enumerate {integer}
112 + * @returns {type.UInt8} per encoded enumerate
113 + */
114 +function writeEnumerates(enumerate) {
115 + return new type.UInt8(enumerate);
116 +}
117 +
118 +/**
119 + * @param s {type.Stream}
120 + * @returns {integer} integer per decoded
121 + */
122 +function readInteger(s) {
123 + var result;
124 + var size = readLength(s);
125 + switch(size) {
126 + case 1:
127 + result = new type.UInt8();
128 + break;
129 + case 2:
130 + result = new type.UInt16Be();
131 + break;
132 + case 4:
133 + result = new type.UInt32Be();
134 + break;
135 + default:
136 + throw new error.UnexpectedFatalError('NODE_RDP_PROTOCOL_T125_PER_BAD_INTEGER_LENGTH');
137 + }
138 + return result.read(s).value;
139 +}
140 +
141 +/**
142 + * @param value {integer}
143 + * @returns {type.Component} per encoded integer
144 + */
145 +function writeInteger(value) {
146 + if(value <= 0xff) {
147 + return new type.Component([writeLength(1), new type.UInt8(value)]);
148 + }
149 + else if(value < 0xffff) {
150 + return new type.Component([writeLength(2), new type.UInt16Be(value)]);
151 + }
152 + else {
153 + return new type.Component([writeLength(4), new type.UInt32Be(value)]);
154 + }
155 +}
156 +
157 +/**
158 + * @param s {type.Stream}
159 + * @param minimum {integer} increment (default 0)
160 + * @returns {integer} per decoded integer 16 bits
161 + */
162 +function readInteger16(s, minimum) {
163 + return new type.UInt16Be().read(s).value + (minimum || 0);
164 +}
165 +
166 +/**
167 + * @param value {integer}
168 + * @param minimum {integer} decrement (default 0)
169 + * @returns {type.UInt16Be} per encoded integer 16 bits
170 + */
171 +function writeInteger16(value, minimum) {
172 + return new type.UInt16Be(value - (minimum || 0));
173 +}
174 +
175 +/**
176 + * Check object identifier
177 + * @param s {type.Stream}
178 + * @param oid {array} object identifier to check
179 + */
180 +function readObjectIdentifier(s, oid) {
181 + var size = readLength(s);
182 + if(size !== 5) {
183 + return false;
184 + }
185 +
186 + var a_oid = [0, 0, 0, 0, 0, 0];
187 + var t12 = new type.UInt8().read(s).value;
188 + a_oid[0] = t12 >> 4;
189 + a_oid[1] = t12 & 0x0f;
190 + a_oid[2] = new type.UInt8().read(s).value;
191 + a_oid[3] = new type.UInt8().read(s).value;
192 + a_oid[4] = new type.UInt8().read(s).value;
193 + a_oid[5] = new type.UInt8().read(s).value;
194 +
195 + for(var i in oid) {
196 + if(oid[i] !== a_oid[i]) return false;
197 + }
198 +
199 + return true;
200 +}
201 +
202 +/**
203 + * @param oid {array} oid to write
204 + * @returns {type.Component} per encoded object identifier
205 + */
206 +function writeObjectIdentifier(oid) {
207 + return new type.Component([new type.UInt8(5), new type.UInt8((oid[0] << 4) & (oid[1] & 0x0f)), new type.UInt8(oid[2]), new type.UInt8(oid[3]), new type.UInt8(oid[4]), new type.UInt8(oid[5])]);
208 +}
209 +
210 +/**
211 + * Read as padding...
212 + * @param s {type.Stream}
213 + * @param minValue
214 + */
215 +function readNumericString(s, minValue) {
216 + var length = readLength(s);
217 + length = (length + minValue + 1) / 2;
218 + s.readPadding(length);
219 +}
220 +
221 +/**
222 + * @param nStr {String}
223 + * @param minValue {integer}
224 + * @returns {type.Component} per encoded numeric string
225 + */
226 +function writeNumericString(nStr, minValue) {
227 + var length = nStr.length;
228 + var mlength = minValue;
229 + if(length - minValue >= 0) {
230 + mlength = length - minValue;
231 + }
232 +
233 + var result = [];
234 +
235 + for(var i = 0; i < length; i += 2) {
236 + var c1 = nStr.charCodeAt(i);
237 + var c2 = 0;
238 + if(i + 1 < length) {
239 + c2 = nStr.charCodeAt(i + 1);
240 + }
241 + else {
242 + c2 = 0x30;
243 + }
244 + c1 = (c1 - 0x30) % 10;
245 + c2 = (c2 - 0x30) % 10;
246 +
247 + result[result.length] = new type.UInt8((c1 << 4) | c2);
248 + }
249 +
250 + return new type.Component([writeLength(mlength), new type.Component(result)]);
251 +}
252 +
253 +/**
254 + * @param s {type.Stream}
255 + * @param length {integer} length of padding
256 + */
257 +function readPadding(s, length) {
258 + s.readPadding(length);
259 +}
260 +
261 +/**
262 + * @param length {integer} length of padding
263 + * @returns {type.BinaryString} per encoded padding
264 + */
265 +function writePadding(length) {
266 + return new type.BinaryString(Buffer.from(Array(length + 1).join("\x00")));
267 +}
268 +
269 +/**
270 + * @param s {type.Stream}
271 + * @param octetStream {String}
272 + * @param minValue {integer} default 0
273 + * @returns {Boolean} true if read octectStream is equal to octetStream
274 + */
275 +function readOctetStream(s, octetStream, minValue) {
276 + var size = readLength(s) + (minValue || 0);
277 + if(size !== octetStream.length) {
278 + return false;
279 + }
280 + for(var i = 0; i < size; i++) {
281 + var c = new type.UInt8().read(s);
282 + if(octetStream.charCodeAt(i) !== c.value) {
283 + return false;
284 + }
285 + }
286 +
287 + return true;
288 +}
289 +
290 +/**
291 + * @param oStr {String}
292 + * @param minValue {integer} default 0
293 + * @returns {type.Component} per encoded octet stream
294 + */
295 +function writeOctetStream(oStr, minValue) {
296 + minValue = minValue || 0;
297 + var length = oStr.length;
298 + var mlength = minValue;
299 +
300 + if(length - minValue >= 0) {
301 + mlength = length - minValue;
302 + }
303 +
304 + result = [];
305 + for(var i = 0; i < length; i++) {
306 + result[result.length] = new type.UInt8(oStr[i]);
307 + }
308 +
309 + return new type.Component([writeLength(mlength), new type.Component(result)]);
310 +}
311 +
312 +/**
313 + * Module exports
314 + */
315 +module.exports = {
316 + readLength : readLength,
317 + writeLength : writeLength,
318 + readChoice : readChoice,
319 + writeChoice : writeChoice,
320 + readSelection : readSelection,
321 + writeSelection : writeSelection,
322 + readNumberOfSet : readNumberOfSet,
323 + writeNumberOfSet : writeNumberOfSet,
324 + readEnumerates : readEnumerates,
325 + writeEnumerates : writeEnumerates,
326 + readInteger : readInteger,
327 + writeInteger : writeInteger,
328 + readInteger16 : readInteger16,
329 + writeInteger16 : writeInteger16,
330 + readObjectIdentifier : readObjectIdentifier,
331 + writeObjectIdentifier : writeObjectIdentifier,
332 + readNumericString : readNumericString,
333 + writeNumericString : writeNumericString,
334 + readPadding : readPadding,
335 + writePadding : writePadding,
336 + readOctetStream : readOctetStream,
337 + writeOctetStream : writeOctetStream
338 +};
\ No newline at end of file
rdp/protocol/tpkt.js new
+171
@@ -0,0 +1,171 @@
1 +/*
2 + * Copyright (c) 2014-2015 Sylvain Peyrefitte
3 + *
4 + * This file is part of node-rdpjs.
5 + *
6 + * node-rdpjs is free software: you can redistribute it and/or modify
7 + * it under the terms of the GNU General Public License as published by
8 + * the Free Software Foundation, either version 3 of the License, or
9 + * (at your option) any later version.
10 + *
11 + * This program is distributed in the hope that it will be useful,
12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 + * GNU General Public License for more details.
15 + *
16 + * You should have received a copy of the GNU General Public License
17 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 + */
19 +
20 +var inherits = require('util').inherits;
21 +var type = require('../core').type;
22 +var events = require('events');
23 +
24 +/**
25 + * Type of tpkt packet
26 + * Fastpath is use to shortcut RDP stack
27 + * @see http://msdn.microsoft.com/en-us/library/cc240621.aspx
28 + * @see http://msdn.microsoft.com/en-us/library/cc240589.aspx
29 + */
30 +var Action = {
31 + FASTPATH_ACTION_FASTPATH : 0x0,
32 + FASTPATH_ACTION_X224 : 0x3
33 +};
34 +
35 +/**
36 + * TPKT layer of rdp stack
37 + */
38 +function TPKT(transport) {
39 + this.transport = transport;
40 + // wait 2 bytes
41 + this.transport.expect(2);
42 + // next state is receive header
43 + var self = this;
44 + this.transport.once('data', function(s) {
45 + self.recvHeader(s);
46 + }).on('close', function() {
47 + self.emit('close');
48 + }).on('error', function (err) {
49 + self.emit('error', err);
50 + });
51 +}
52 +
53 +/**
54 + * inherit from a packet layer
55 + */
56 +inherits(TPKT, events.EventEmitter);
57 +
58 +/**
59 + * Receive correct packet as expected
60 + * @param s {type.Stream}
61 + */
62 +TPKT.prototype.recvHeader = function (s) {
63 + var version = new type.UInt8().read(s).value;
64 + var self = this;
65 + if(version === Action.FASTPATH_ACTION_X224) {
66 + new type.UInt8().read(s);
67 + this.transport.expect(2);
68 + this.transport.once('data', function(s) {
69 + self.recvExtendedHeader(s);
70 + });
71 + }
72 + else {
73 + this.secFlag = ((version >> 6) & 0x3);
74 + var length = new type.UInt8().read(s).value;
75 + if (length & 0x80) {
76 + this.transport.expect(1);
77 + this.transport.once('data', function(s) {
78 + self.recvExtendedFastPathHeader(s, length);
79 + });
80 + }
81 + else {
82 + this.transport.expect(length - 2);
83 + this.transport.once('data', function(s) {
84 + self.recvFastPath(s);
85 + });
86 + }
87 + }
88 +};
89 +
90 +/**
91 + * Receive second part of header packet
92 + * @param s {type.Stream}
93 + */
94 +TPKT.prototype.recvExtendedHeader = function (s) {
95 + var size = new type.UInt16Be().read(s);
96 + this.transport.expect(size.value - 4);
97 + //next state receive packet
98 + var self = this;
99 + this.transport.once('data', function(s) {
100 + self.recvData(s);
101 + });
102 +};
103 +
104 +/**
105 + * Receive data available for presentation layer
106 + * @param s {type.Stream}
107 + */
108 +TPKT.prototype.recvData = function (s) {
109 + this.emit('data', s);
110 + this.transport.expect(2);
111 + //next state receive header
112 + var self = this;
113 + this.transport.once('data', function(s) {
114 + self.recvHeader(s);
115 + });
116 +};
117 +
118 +/**
119 + * Read extended fastpath header
120 + * @param s {type.Stream}
121 + */
122 +TPKT.prototype.recvExtendedFastPathHeader = function (s, length) {
123 + var rightPart = new type.UInt8().read(s).value;
124 + var leftPart = length & ~0x80;
125 + var packetSize = (leftPart << 8) + rightPart;
126 +
127 + var self = this;
128 + this.transport.expect(packetSize - 3);
129 + this.transport.once('data', function(s) {
130 + self.recvFastPath(s);
131 + });
132 +};
133 +
134 +/**
135 + * Read fast path data
136 + * @param s {type.Stream}
137 + */
138 +TPKT.prototype.recvFastPath = function (s) {
139 + this.emit('fastPathData', this.secFlag, s);
140 + var self = this;
141 + this.transport.expect(2);
142 + this.transport.once('data', function(s) {
143 + self.recvHeader(s);
144 + });
145 +};
146 +
147 +/**
148 + * Send message throught TPKT layer
149 + * @param message {type.*}
150 + */
151 +TPKT.prototype.send = function(message) {
152 + this.transport.send(new type.Component([
153 + new type.UInt8(Action.FASTPATH_ACTION_X224),
154 + new type.UInt8(0),
155 + new type.UInt16Be(message.size() + 4),
156 + message
157 + ]));
158 +};
159 +
160 +/**
161 + * close stack
162 + */
163 +TPKT.prototype.close = function() {
164 + this.transport.close();
165 +};
166 +
167 +/**
168 + * Module exports
169 + */
170 +module.exports = TPKT;
171 +
rdp/protocol/x224.js new
+346
@@ -0,0 +1,346 @@
1 +/*
2 + * Copyright (c) 2014-2015 Sylvain Peyrefitte
3 + *
4 + * This file is part of node-rdpjs.
5 + *
6 + * node-rdpjs is free software: you can redistribute it and/or modify
7 + * it under the terms of the GNU General Public License as published by
8 + * the Free Software Foundation, either version 3 of the License, or
9 + * (at your option) any later version.
10 + *
11 + * This program is distributed in the hope that it will be useful,
12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 + * GNU General Public License for more details.
15 + *
16 + * You should have received a copy of the GNU General Public License
17 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 + */
19 +
20 +var inherits = require('util').inherits;
21 +var events = require('events');
22 +var type = require('../core').type;
23 +var log = require('../core').log;
24 +var error = require('../core').error;
25 +
26 +/**
27 + * Message type present in X224 packet header
28 + */
29 +var MessageType = {
30 + X224_TPDU_CONNECTION_REQUEST : 0xE0,
31 + X224_TPDU_CONNECTION_CONFIRM : 0xD0,
32 + X224_TPDU_DISCONNECT_REQUEST : 0x80,
33 + X224_TPDU_DATA : 0xF0,
34 + X224_TPDU_ERROR : 0x70
35 +};
36 +
37 +/**
38 + * Type of negotiation present in negotiation packet
39 + */
40 +var NegotiationType = {
41 + TYPE_RDP_NEG_REQ : 0x01,
42 + TYPE_RDP_NEG_RSP : 0x02,
43 + TYPE_RDP_NEG_FAILURE : 0x03
44 +};
45 +
46 +/**
47 + * Protocols available for x224 layer
48 + */
49 +var Protocols = {
50 + PROTOCOL_RDP : 0x00000000,
51 + PROTOCOL_SSL : 0x00000001,
52 + PROTOCOL_HYBRID : 0x00000002,
53 + PROTOCOL_HYBRID_EX : 0x00000008
54 +};
55 +
56 +/**
57 + * Use to negotiate security layer of RDP stack
58 + * In node-rdpjs only ssl is available
59 + * @param opt {object} component type options
60 + * @see request -> http://msdn.microsoft.com/en-us/library/cc240500.aspx
61 + * @see response -> http://msdn.microsoft.com/en-us/library/cc240506.aspx
62 + * @see failure ->http://msdn.microsoft.com/en-us/library/cc240507.aspx
63 + */
64 +function negotiation(opt) {
65 + var self = {
66 + type : new type.UInt8(),
67 + flag : new type.UInt8(),
68 + length : new type.UInt16Le(0x0008, { constant : true }),
69 + result : new type.UInt32Le()
70 + };
71 + return new type.Component(self, opt);
72 +}
73 +
74 +/**
75 + * X224 client connection request
76 + * @param opt {object} component type options
77 + * @see http://msdn.microsoft.com/en-us/library/cc240470.aspx
78 + */
79 +function clientConnectionRequestPDU(opt, cookie) {
80 + var self = {
81 + len : new type.UInt8(function() {
82 + return new type.Component(self).size() - 1;
83 + }),
84 + code : new type.UInt8(MessageType.X224_TPDU_CONNECTION_REQUEST, { constant : true }),
85 + padding : new type.Component([new type.UInt16Le(), new type.UInt16Le(), new type.UInt8()]),
86 + cookie : cookie || new type.Factory( function (s) {
87 + var offset = 0;
88 + while (true) {
89 + var token = s.buffer.readUInt16LE(s.offset + offset);
90 + if (token === 0x0a0d) {
91 + self.cookie = new type.BinaryString(null, { readLength : new type.CallableValue(offset + 2) }).read(s);
92 + return;
93 + }
94 + else {
95 + offset += 1;
96 + }
97 + }
98 + }, { conditional : function () {
99 + return self.len.value > 14;
100 + }}),
101 + protocolNeg : negotiation({ optional : true })
102 + };
103 +
104 + return new type.Component(self, opt);
105 +}
106 +
107 +/**
108 + * X224 Server connection confirm
109 + * @param opt {object} component type options
110 + * @see http://msdn.microsoft.com/en-us/library/cc240506.aspx
111 + */
112 +function serverConnectionConfirm(opt) {
113 + var self = {
114 + len : new type.UInt8(function() {
115 + return new type.Component(self).size() - 1;
116 + }),
117 + code : new type.UInt8(MessageType.X224_TPDU_CONNECTION_CONFIRM, { constant : true }),
118 + padding : new type.Component([new type.UInt16Le(), new type.UInt16Le(), new type.UInt8()]),
119 + protocolNeg : negotiation({ optional : true })
120 + };
121 +
122 + return new type.Component(self, opt);
123 +}
124 +
125 +/**
126 + * Header of each data message from x224 layer
127 + * @returns {type.Component}
128 + */
129 +function x224DataHeader() {
130 + var self = {
131 + header : new type.UInt8(2),
132 + messageType : new type.UInt8(MessageType.X224_TPDU_DATA, { constant : true }),
133 + separator : new type.UInt8(0x80, { constant : true })
134 + };
135 + return new type.Component(self);
136 +}
137 +
138 +/**
139 + * Common X224 Automata
140 + * @param presentation {Layer} presentation layer
141 + */
142 +function X224(transport) {
143 + this.transport = transport;
144 + this.requestedProtocol = Protocols.PROTOCOL_SSL | Protocols.PROTOCOL_HYBRID;
145 + this.selectedProtocol = Protocols.PROTOCOL_SSL | Protocols.PROTOCOL_HYBRID;
146 +
147 + var self = this;
148 + this.transport.on('close', function() {
149 + self.emit('close');
150 + }).on('error', function (err) {
151 + self.emit('error', err);
152 + });
153 +}
154 +
155 +//inherit from Layer
156 +inherits(X224, events.EventEmitter);
157 +
158 +/**
159 + * Main data received function
160 + * after connection sequence
161 + * @param s {type.Stream} stream formated from transport layer
162 + */
163 +X224.prototype.recvData = function(s) {
164 + // check header
165 + x224DataHeader().read(s);
166 + this.emit('data', s);
167 +};
168 +
169 +/**
170 + * Format message from x224 layer to transport layer
171 + * @param message {type}
172 + * @returns {type.Component} x224 formated message
173 + */
174 +X224.prototype.send = function(message) {
175 + this.transport.send(new type.Component([x224DataHeader(), message]));
176 +};
177 +
178 +/**
179 + * Client x224 automata
180 + * @param transport {events.EventEmitter} (bind data events)
181 + */
182 +function Client(transport, config) {
183 + this.config = config;
184 + X224.call(this, transport);
185 +}
186 +
187 +//inherit from X224 automata
188 +inherits(Client, X224);
189 +
190 +/**
191 + * Client automata connect event
192 + */
193 +Client.prototype.connect = function() {
194 + var message = clientConnectionRequestPDU(null, new type.BinaryString());
195 + message.obj.protocolNeg.obj.type.value = NegotiationType.TYPE_RDP_NEG_REQ;
196 + message.obj.protocolNeg.obj.result.value = this.requestedProtocol;
197 + this.transport.send(message);
198 +
199 + // next state wait connection confirm packet
200 + var self = this;
201 + this.transport.once('data', function(s) {
202 + self.recvConnectionConfirm(s);
203 + });
204 +};
205 +
206 +/**
207 + * close stack
208 + */
209 +Client.prototype.close = function() {
210 + this.transport.close();
211 +};
212 +
213 +/**
214 + * Receive connection from server
215 + * @param s {Stream}
216 + */
217 +Client.prototype.recvConnectionConfirm = function(s) {
218 + var message = serverConnectionConfirm().read(s);
219 +
220 + if (message.obj.protocolNeg.obj.type.value == NegotiationType.TYPE_RDP_NEG_FAILURE) {
221 + throw new error.ProtocolError('NODE_RDP_PROTOCOL_X224_NEG_FAILURE',
222 + 'Failure code:' + message.obj.protocolNeg.obj.result.value + " (see https://msdn.microsoft.com/en-us/library/cc240507.aspx)");
223 + }
224 +
225 + if (message.obj.protocolNeg.obj.type.value == NegotiationType.TYPE_RDP_NEG_RSP) {
226 + this.selectedProtocol = message.obj.protocolNeg.obj.result.value;
227 + }
228 +
229 + if ([Protocols.PROTOCOL_HYBRID_EX].indexOf(this.selectedProtocol) !== -1) {
230 + throw new error.ProtocolError('NODE_RDP_PROTOCOL_X224_NLA_NOT_SUPPORTED');
231 + }
232 +
233 + if (this.selectedProtocol == Protocols.PROTOCOL_RDP) {
234 + log.debug("RDP standard security selected");
235 + return;
236 + }
237 +
238 + if (this.selectedProtocol == Protocols.PROTOCOL_HYBRID) {
239 + log.debug("NLA security layer selected");
240 + var self = this;
241 + var transportEx = this.transport.transport;
242 + this.transport.transport.startTLS(function () {
243 + //console.log('TLS connected, start cssp_connect()');
244 + var NLA = require('./nla');
245 + self.nla = new NLA(transportEx, function () { self.nlaCompleted(); }, self.config.domain, self.config.userName, self.config.password);
246 + self.nla.sendNegotiateMessage();
247 + });
248 + return;
249 + }
250 +
251 + // finish connection sequence
252 + var self = this;
253 + this.transport.on('data', function(s) {
254 + self.recvData(s);
255 + });
256 +
257 + if (this.selectedProtocol == Protocols.PROTOCOL_SSL) {
258 + log.debug("SSL standard security selected");
259 + this.transport.transport.startTLS(function() {
260 + self.emit('connect', self.selectedProtocol);
261 + });
262 + return;
263 + }
264 +};
265 +
266 +/**
267 + * Called when NLA is completed
268 + */
269 +Client.prototype.nlaCompleted = function () {
270 + const self = this;
271 + delete self.nla;
272 + this.transport.on('data', function (s) { self.recvData(s); });
273 + this.emit('connect', this.selectedProtocol);
274 +}
275 +
276 +
277 +/**
278 + * Server x224 automata
279 + */
280 +function Server(transport, keyFilePath, crtFilePath) {
281 + X224.call(this, transport);
282 + this.keyFilePath = keyFilePath;
283 + this.crtFilePath = crtFilePath;
284 + var self = this;
285 + this.transport.once('data', function (s) {
286 + self.recvConnectionRequest(s);
287 + });
288 +}
289 +
290 +//inherit from X224 automata
291 +inherits(Server, X224);
292 +
293 +/**
294 + * @see http://msdn.microsoft.com/en-us/library/cc240470.aspx
295 + * @param s {type.Stream}
296 + */
297 +Server.prototype.recvConnectionRequest = function (s) {
298 + var request = clientConnectionRequestPDU().read(s);
299 + if (!request.obj.protocolNeg.isReaded) {
300 + throw new Error('NODE_RDP_PROTOCOL_X224_NO_BASIC_SECURITY_LAYER');
301 + }
302 +
303 + this.requestedProtocol = request.obj.protocolNeg.obj.result.value;
304 + this.selectedProtocol = this.requestedProtocol & Protocols.PROTOCOL_SSL;
305 +
306 + if (!(this.selectedProtocol & Protocols.PROTOCOL_SSL)) {
307 + var confirm = serverConnectionConfirm();
308 + confirm.obj.protocolNeg.obj.type.value = NegociationType.TYPE_RDP_NEG_FAILURE;
309 + confirm.obj.protocolNeg.obj.result.value = NegotiationFailureCode.SSL_REQUIRED_BY_SERVER;
310 + this.transport.send(confirm);
311 + this.close();
312 + }
313 + else {
314 + this.sendConnectionConfirm();
315 + }
316 +};
317 +
318 +/**
319 + * Start SSL connection if needed
320 + * @see http://msdn.microsoft.com/en-us/library/cc240501.aspx
321 + */
322 +Server.prototype.sendConnectionConfirm = function () {
323 + var confirm = serverConnectionConfirm();
324 + confirm.obj.protocolNeg.obj.type.value = NegotiationType.TYPE_RDP_NEG_RSP;
325 + confirm.obj.protocolNeg.obj.result.value = this.selectedProtocol;
326 + this.transport.send(confirm);
327 +
328 + // finish connection sequence
329 + var self = this;
330 + this.transport.on('data', function(s) {
331 + self.recvData(s);
332 + });
333 +
334 + this.transport.transport.listenTLS(this.keyFilePath, this.crtFilePath, function() {
335 + log.debug('start SSL connection');
336 + self.emit('connect', self.requestedProtocol);
337 + });
338 +};
339 +
340 +/**
341 + * Module exports
342 + */
343 +module.exports = {
344 + Client : Client,
345 + Server : Server
346 +};
rdp/security/index.js new
+26
@@ -0,0 +1,26 @@
1 +/*
2 + * Copyright (c) 2014-2015 Sylvain Peyrefitte
3 + *
4 + * This file is part of node-rdpjs.
5 + *
6 + * node-rdpjs is free software: you can redistribute it and/or modify
7 + * it under the terms of the GNU General Public License as published by
8 + * the Free Software Foundation, either version 3 of the License, or
9 + * (at your option) any later version.
10 + *
11 + * This program is distributed in the hope that it will be useful,
12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 + * GNU General Public License for more details.
15 + *
16 + * You should have received a copy of the GNU General Public License
17 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 + */
19 +
20 +var x509 = require('./x509');
21 +var rsa = require('./rsa');
22 +
23 +module.exports = {
24 + x509 : x509,
25 + rsa : rsa
26 +};
rdp/security/jsbn.js new
+1543
@@ -0,0 +1,1543 @@
1 +/*
2 + * Basic JavaScript BN library - subset useful for RSA encryption.
3 + *
4 + * Copyright (c) 2003-2005 Tom Wu
5 + * All Rights Reserved.
6 + *
7 + * Permission is hereby granted, free of charge, to any person obtaining
8 + * a copy of this software and associated documentation files (the
9 + * "Software"), to deal in the Software without restriction, including
10 + * without limitation the rights to use, copy, modify, merge, publish,
11 + * distribute, sublicense, and/or sell copies of the Software, and to
12 + * permit persons to whom the Software is furnished to do so, subject to
13 + * the following conditions:
14 + *
15 + * The above copyright notice and this permission notice shall be
16 + * included in all copies or substantial portions of the Software.
17 + *
18 + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
19 + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
20 + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
21 + *
22 + * IN NO EVENT SHALL TOM WU BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
23 + * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
24 + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF
25 + * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT
26 + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
27 + *
28 + * In addition, the following condition applies:
29 + *
30 + * All redistributions must retain an intact copy of this copyright notice
31 + * and disclaimer.
32 + */
33 +
34 +/*
35 + * Added Node.js Buffers support
36 + * 2014 rzcoder
37 + */
38 +
39 +var crypt = require('crypto');
40 +
41 +//var isNumber = require('lodash.isnumber'); // Remove this dependency to limit supply chain risks
42 +function isObjectLike(value) { return !!value && typeof value == 'object'; }
43 +const isNumber = function isNumber(value) { return typeof value == 'number' || (isObjectLike(value) && Object.prototype.toString.call(value) == '[object Number]'); }
44 +
45 +// Bits per digit
46 +var dbits;
47 +
48 +// JavaScript engine analysis
49 +var canary = 0xdeadbeefcafe;
50 +var j_lm = ((canary & 0xffffff) == 0xefcafe);
51 +
52 +// (public) Constructor
53 +function BigInteger(a, b) {
54 + if (a != null) {
55 + if ("number" == typeof a) {
56 + this.fromNumber(a, b);
57 + } else if (Buffer.isBuffer(a)) {
58 + this.fromBuffer(a);
59 + } else if (b == null && "string" != typeof a) {
60 + this.fromByteArray(a);
61 + } else {
62 + this.fromString(a, b);
63 + }
64 + }
65 +}
66 +
67 +// return new, unset BigInteger
68 +function nbi() {
69 + return new BigInteger(null);
70 +}
71 +
72 +// am: Compute w_j += (x*this_i), propagate carries,
73 +// c is initial carry, returns final carry.
74 +// c < 3*dvalue, x < 2*dvalue, this_i < dvalue
75 +// We need to select the fastest one that works in this environment.
76 +
77 +// am1: use a single mult and divide to get the high bits,
78 +// max digit bits should be 26 because
79 +// max internal value = 2*dvalue^2-2*dvalue (< 2^53)
80 +function am1(i, x, w, j, c, n) {
81 + while (--n >= 0) {
82 + var v = x * this[i++] + w[j] + c;
83 + c = Math.floor(v / 0x4000000);
84 + w[j++] = v & 0x3ffffff;
85 + }
86 + return c;
87 +}
88 +// am2 avoids a big mult-and-extract completely.
89 +// Max digit bits should be <= 30 because we do bitwise ops
90 +// on values up to 2*hdvalue^2-hdvalue-1 (< 2^31)
91 +function am2(i, x, w, j, c, n) {
92 + var xl = x & 0x7fff, xh = x >> 15;
93 + while (--n >= 0) {
94 + var l = this[i] & 0x7fff;
95 + var h = this[i++] >> 15;
96 + var m = xh * l + h * xl;
97 + l = xl * l + ((m & 0x7fff) << 15) + w[j] + (c & 0x3fffffff);
98 + c = (l >>> 30) + (m >>> 15) + xh * h + (c >>> 30);
99 + w[j++] = l & 0x3fffffff;
100 + }
101 + return c;
102 +}
103 +// Alternately, set max digit bits to 28 since some
104 +// browsers slow down when dealing with 32-bit numbers.
105 +function am3(i, x, w, j, c, n) {
106 + var xl = x & 0x3fff, xh = x >> 14;
107 + while (--n >= 0) {
108 + var l = this[i] & 0x3fff;
109 + var h = this[i++] >> 14;
110 + var m = xh * l + h * xl;
111 + l = xl * l + ((m & 0x3fff) << 14) + w[j] + c;
112 + c = (l >> 28) + (m >> 14) + xh * h;
113 + w[j++] = l & 0xfffffff;
114 + }
115 + return c;
116 +}
117 +
118 +// We need to select the fastest one that works in this environment.
119 +//if (j_lm && (navigator.appName == "Microsoft Internet Explorer")) {
120 +// BigInteger.prototype.am = am2;
121 +// dbits = 30;
122 +//} else if (j_lm && (navigator.appName != "Netscape")) {
123 +// BigInteger.prototype.am = am1;
124 +// dbits = 26;
125 +//} else { // Mozilla/Netscape seems to prefer am3
126 +// BigInteger.prototype.am = am3;
127 +// dbits = 28;
128 +//}
129 +
130 +// For node.js, we pick am3 with max dbits to 28.
131 +BigInteger.prototype.am = am3;
132 +dbits = 28;
133 +
134 +BigInteger.prototype.DB = dbits;
135 +BigInteger.prototype.DM = ((1 << dbits) - 1);
136 +BigInteger.prototype.DV = (1 << dbits);
137 +
138 +var BI_FP = 52;
139 +BigInteger.prototype.FV = Math.pow(2, BI_FP);
140 +BigInteger.prototype.F1 = BI_FP - dbits;
141 +BigInteger.prototype.F2 = 2 * dbits - BI_FP;
142 +
143 +// Digit conversions
144 +var BI_RM = "0123456789abcdefghijklmnopqrstuvwxyz";
145 +var BI_RC = new Array();
146 +var rr, vv;
147 +rr = "0".charCodeAt(0);
148 +for (vv = 0; vv <= 9; ++vv) BI_RC[rr++] = vv;
149 +rr = "a".charCodeAt(0);
150 +for (vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv;
151 +rr = "A".charCodeAt(0);
152 +for (vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv;
153 +
154 +function int2char(n) {
155 + return BI_RM.charAt(n);
156 +}
157 +function intAt(s, i) {
158 + var c = BI_RC[s.charCodeAt(i)];
159 + return (c == null) ? -1 : c;
160 +}
161 +
162 +// (protected) copy this to r
163 +function bnpCopyTo(r) {
164 + for (var i = this.t - 1; i >= 0; --i) r[i] = this[i];
165 + r.t = this.t;
166 + r.s = this.s;
167 +}
168 +
169 +// (protected) set from integer value x, -DV <= x < DV
170 +function bnpFromInt(x) {
171 + this.t = 1;
172 + this.s = (x < 0) ? -1 : 0;
173 + if (x > 0) this[0] = x;
174 + else if (x < -1) this[0] = x + DV;
175 + else this.t = 0;
176 +}
177 +
178 +// return bigint initialized to value
179 +function nbv(i) {
180 + var r = nbi();
181 + r.fromInt(i);
182 + return r;
183 +}
184 +
185 +// (protected) set from string and radix
186 +function bnpFromString(data, radix, unsigned) {
187 + var k;
188 + switch (radix) {
189 + case 2:
190 + k = 1;
191 + break;
192 + case 4:
193 + k = 2;
194 + break;
195 + case 8:
196 + k = 3;
197 + break;
198 + case 16:
199 + k = 4;
200 + break;
201 + case 32:
202 + k = 5;
203 + break;
204 + case 256:
205 + k = 8;
206 + break;
207 + default:
208 + this.fromRadix(data, radix);
209 + return;
210 + }
211 +
212 + this.t = 0;
213 + this.s = 0;
214 +
215 + var i = data.length;
216 + var mi = false;
217 + var sh = 0;
218 +
219 + while (--i >= 0) {
220 + var x = (k == 8) ? data[i] & 0xff : intAt(data, i);
221 + if (x < 0) {
222 + if (data.charAt(i) == "-") mi = true;
223 + continue;
224 + }
225 + mi = false;
226 + if (sh === 0)
227 + this[this.t++] = x;
228 + else if (sh + k > this.DB) {
229 + this[this.t - 1] |= (x & ((1 << (this.DB - sh)) - 1)) << sh;
230 + this[this.t++] = (x >> (this.DB - sh));
231 + }
232 + else
233 + this[this.t - 1] |= x << sh;
234 + sh += k;
235 + if (sh >= this.DB) sh -= this.DB;
236 + }
237 + if ((!unsigned) && k == 8 && (data[0] & 0x80) != 0) {
238 + this.s = -1;
239 + if (sh > 0) this[this.t - 1] |= ((1 << (this.DB - sh)) - 1) << sh;
240 + }
241 + this.clamp();
242 + if (mi) BigInteger.ZERO.subTo(this, this);
243 +}
244 +
245 +function bnpFromByteArray(a, unsigned) {
246 + this.fromString(a, 256, unsigned)
247 +}
248 +
249 +function bnpFromBuffer(a) {
250 + this.fromString(a, 256, true)
251 +}
252 +
253 +// (protected) clamp off excess high words
254 +function bnpClamp() {
255 + var c = this.s & this.DM;
256 + while (this.t > 0 && this[this.t - 1] == c) --this.t;
257 +}
258 +
259 +// (public) return string representation in given radix
260 +function bnToString(b) {
261 + if (this.s < 0) return "-" + this.negate().toString(b);
262 + var k;
263 + if (b == 16) k = 4;
264 + else if (b == 8) k = 3;
265 + else if (b == 2) k = 1;
266 + else if (b == 32) k = 5;
267 + else if (b == 4) k = 2;
268 + else return this.toRadix(b);
269 + var km = (1 << k) - 1, d, m = false, r = "", i = this.t;
270 + var p = this.DB - (i * this.DB) % k;
271 + if (i-- > 0) {
272 + if (p < this.DB && (d = this[i] >> p) > 0) {
273 + m = true;
274 + r = int2char(d);
275 + }
276 + while (i >= 0) {
277 + if (p < k) {
278 + d = (this[i] & ((1 << p) - 1)) << (k - p);
279 + d |= this[--i] >> (p += this.DB - k);
280 + }
281 + else {
282 + d = (this[i] >> (p -= k)) & km;
283 + if (p <= 0) {
284 + p += this.DB;
285 + --i;
286 + }
287 + }
288 + if (d > 0) m = true;
289 + if (m) r += int2char(d);
290 + }
291 + }
292 + return m ? r : "0";
293 +}
294 +
295 +// (public) -this
296 +function bnNegate() {
297 + var r = nbi();
298 + BigInteger.ZERO.subTo(this, r);
299 + return r;
300 +}
301 +
302 +// (public) |this|
303 +function bnAbs() {
304 + return (this.s < 0) ? this.negate() : this;
305 +}
306 +
307 +// (public) return + if this > a, - if this < a, 0 if equal
308 +function bnCompareTo(a) {
309 + var r = this.s - a.s;
310 + if (r != 0) return r;
311 + var i = this.t;
312 + r = i - a.t;
313 + if (r != 0) return (this.s < 0) ? -r : r;
314 + while (--i >= 0) if ((r = this[i] - a[i]) != 0) return r;
315 + return 0;
316 +}
317 +
318 +// returns bit length of the integer x
319 +function nbits(x) {
320 + var r = 1, t;
321 + if ((t = x >>> 16) != 0) {
322 + x = t;
323 + r += 16;
324 + }
325 + if ((t = x >> 8) != 0) {
326 + x = t;
327 + r += 8;
328 + }
329 + if ((t = x >> 4) != 0) {
330 + x = t;
331 + r += 4;
332 + }
333 + if ((t = x >> 2) != 0) {
334 + x = t;
335 + r += 2;
336 + }
337 + if ((t = x >> 1) != 0) {
338 + x = t;
339 + r += 1;
340 + }
341 + return r;
342 +}
343 +
344 +// (public) return the number of bits in "this"
345 +function bnBitLength() {
346 + if (this.t <= 0) return 0;
347 + return this.DB * (this.t - 1) + nbits(this[this.t - 1] ^ (this.s & this.DM));
348 +}
349 +
350 +// (protected) r = this << n*DB
351 +function bnpDLShiftTo(n, r) {
352 + var i;
353 + for (i = this.t - 1; i >= 0; --i) r[i + n] = this[i];
354 + for (i = n - 1; i >= 0; --i) r[i] = 0;
355 + r.t = this.t + n;
356 + r.s = this.s;
357 +}
358 +
359 +// (protected) r = this >> n*DB
360 +function bnpDRShiftTo(n, r) {
361 + for (var i = n; i < this.t; ++i) r[i - n] = this[i];
362 + r.t = Math.max(this.t - n, 0);
363 + r.s = this.s;
364 +}
365 +
366 +// (protected) r = this << n
367 +function bnpLShiftTo(n, r) {
368 + var bs = n % this.DB;
369 + var cbs = this.DB - bs;
370 + var bm = (1 << cbs) - 1;
371 + var ds = Math.floor(n / this.DB), c = (this.s << bs) & this.DM, i;
372 + for (i = this.t - 1; i >= 0; --i) {
373 + r[i + ds + 1] = (this[i] >> cbs) | c;
374 + c = (this[i] & bm) << bs;
375 + }
376 + for (i = ds - 1; i >= 0; --i) r[i] = 0;
377 + r[ds] = c;
378 + r.t = this.t + ds + 1;
379 + r.s = this.s;
380 + r.clamp();
381 +}
382 +
383 +// (protected) r = this >> n
384 +function bnpRShiftTo(n, r) {
385 + r.s = this.s;
386 + var ds = Math.floor(n / this.DB);
387 + if (ds >= this.t) {
388 + r.t = 0;
389 + return;
390 + }
391 + var bs = n % this.DB;
392 + var cbs = this.DB - bs;
393 + var bm = (1 << bs) - 1;
394 + r[0] = this[ds] >> bs;
395 + for (var i = ds + 1; i < this.t; ++i) {
396 + r[i - ds - 1] |= (this[i] & bm) << cbs;
397 + r[i - ds] = this[i] >> bs;
398 + }
399 + if (bs > 0) r[this.t - ds - 1] |= (this.s & bm) << cbs;
400 + r.t = this.t - ds;
401 + r.clamp();
402 +}
403 +
404 +// (protected) r = this - a
405 +function bnpSubTo(a, r) {
406 + var i = 0, c = 0, m = Math.min(a.t, this.t);
407 + while (i < m) {
408 + c += this[i] - a[i];
409 + r[i++] = c & this.DM;
410 + c >>= this.DB;
411 + }
412 + if (a.t < this.t) {
413 + c -= a.s;
414 + while (i < this.t) {
415 + c += this[i];
416 + r[i++] = c & this.DM;
417 + c >>= this.DB;
418 + }
419 + c += this.s;
420 + }
421 + else {
422 + c += this.s;
423 + while (i < a.t) {
424 + c -= a[i];
425 + r[i++] = c & this.DM;
426 + c >>= this.DB;
427 + }
428 + c -= a.s;
429 + }
430 + r.s = (c < 0) ? -1 : 0;
431 + if (c < -1) r[i++] = this.DV + c;
432 + else if (c > 0) r[i++] = c;
433 + r.t = i;
434 + r.clamp();
435 +}
436 +
437 +// (protected) r = this * a, r != this,a (HAC 14.12)
438 +// "this" should be the larger one if appropriate.
439 +function bnpMultiplyTo(a, r) {
440 + var x = this.abs(), y = a.abs();
441 + var i = x.t;
442 + r.t = i + y.t;
443 + while (--i >= 0) r[i] = 0;
444 + for (i = 0; i < y.t; ++i) r[i + x.t] = x.am(0, y[i], r, i, 0, x.t);
445 + r.s = 0;
446 + r.clamp();
447 + if (this.s != a.s) BigInteger.ZERO.subTo(r, r);
448 +}
449 +
450 +// (protected) r = this^2, r != this (HAC 14.16)
451 +function bnpSquareTo(r) {
452 + var x = this.abs();
453 + var i = r.t = 2 * x.t;
454 + while (--i >= 0) r[i] = 0;
455 + for (i = 0; i < x.t - 1; ++i) {
456 + var c = x.am(i, x[i], r, 2 * i, 0, 1);
457 + if ((r[i + x.t] += x.am(i + 1, 2 * x[i], r, 2 * i + 1, c, x.t - i - 1)) >= x.DV) {
458 + r[i + x.t] -= x.DV;
459 + r[i + x.t + 1] = 1;
460 + }
461 + }
462 + if (r.t > 0) r[r.t - 1] += x.am(i, x[i], r, 2 * i, 0, 1);
463 + r.s = 0;
464 + r.clamp();
465 +}
466 +
467 +// (protected) divide this by m, quotient and remainder to q, r (HAC 14.20)
468 +// r != q, this != m. q or r may be null.
469 +function bnpDivRemTo(m, q, r) {
470 + var pm = m.abs();
471 + if (pm.t <= 0) return;
472 + var pt = this.abs();
473 + if (pt.t < pm.t) {
474 + if (q != null) q.fromInt(0);
475 + if (r != null) this.copyTo(r);
476 + return;
477 + }
478 + if (r == null) r = nbi();
479 + var y = nbi(), ts = this.s, ms = m.s;
480 + var nsh = this.DB - nbits(pm[pm.t - 1]); // normalize modulus
481 + if (nsh > 0) {
482 + pm.lShiftTo(nsh, y);
483 + pt.lShiftTo(nsh, r);
484 + }
485 + else {
486 + pm.copyTo(y);
487 + pt.copyTo(r);
488 + }
489 + var ys = y.t;
490 + var y0 = y[ys - 1];
491 + if (y0 === 0) return;
492 + var yt = y0 * (1 << this.F1) + ((ys > 1) ? y[ys - 2] >> this.F2 : 0);
493 + var d1 = this.FV / yt, d2 = (1 << this.F1) / yt, e = 1 << this.F2;
494 + var i = r.t, j = i - ys, t = (q == null) ? nbi() : q;
495 + y.dlShiftTo(j, t);
496 + if (r.compareTo(t) >= 0) {
497 + r[r.t++] = 1;
498 + r.subTo(t, r);
499 + }
500 + BigInteger.ONE.dlShiftTo(ys, t);
501 + t.subTo(y, y); // "negative" y so we can replace sub with am later
502 + while (y.t < ys) y[y.t++] = 0;
503 + while (--j >= 0) {
504 + // Estimate quotient digit
505 + var qd = (r[--i] == y0) ? this.DM : Math.floor(r[i] * d1 + (r[i - 1] + e) * d2);
506 + if ((r[i] += y.am(0, qd, r, j, 0, ys)) < qd) { // Try it out
507 + y.dlShiftTo(j, t);
508 + r.subTo(t, r);
509 + while (r[i] < --qd) r.subTo(t, r);
510 + }
511 + }
512 + if (q != null) {
513 + r.drShiftTo(ys, q);
514 + if (ts != ms) BigInteger.ZERO.subTo(q, q);
515 + }
516 + r.t = ys;
517 + r.clamp();
518 + if (nsh > 0) r.rShiftTo(nsh, r); // Denormalize remainder
519 + if (ts < 0) BigInteger.ZERO.subTo(r, r);
520 +}
521 +
522 +// (public) this mod a
523 +function bnMod(a) {
524 + var r = nbi();
525 + this.abs().divRemTo(a, null, r);
526 + if (this.s < 0 && r.compareTo(BigInteger.ZERO) > 0) a.subTo(r, r);
527 + return r;
528 +}
529 +
530 +// Modular reduction using "classic" algorithm
531 +function Classic(m) {
532 + this.m = m;
533 +}
534 +function cConvert(x) {
535 + if (x.s < 0 || x.compareTo(this.m) >= 0) return x.mod(this.m);
536 + else return x;
537 +}
538 +function cRevert(x) {
539 + return x;
540 +}
541 +function cReduce(x) {
542 + x.divRemTo(this.m, null, x);
543 +}
544 +function cMulTo(x, y, r) {
545 + x.multiplyTo(y, r);
546 + this.reduce(r);
547 +}
548 +function cSqrTo(x, r) {
549 + x.squareTo(r);
550 + this.reduce(r);
551 +}
552 +
553 +Classic.prototype.convert = cConvert;
554 +Classic.prototype.revert = cRevert;
555 +Classic.prototype.reduce = cReduce;
556 +Classic.prototype.mulTo = cMulTo;
557 +Classic.prototype.sqrTo = cSqrTo;
558 +
559 +// (protected) return "-1/this % 2^DB"; useful for Mont. reduction
560 +// justification:
561 +// xy == 1 (mod m)
562 +// xy = 1+km
563 +// xy(2-xy) = (1+km)(1-km)
564 +// x[y(2-xy)] = 1-k^2m^2
565 +// x[y(2-xy)] == 1 (mod m^2)
566 +// if y is 1/x mod m, then y(2-xy) is 1/x mod m^2
567 +// should reduce x and y(2-xy) by m^2 at each step to keep size bounded.
568 +// JS multiply "overflows" differently from C/C++, so care is needed here.
569 +function bnpInvDigit() {
570 + if (this.t < 1) return 0;
571 + var x = this[0];
572 + if ((x & 1) === 0) return 0;
573 + var y = x & 3; // y == 1/x mod 2^2
574 + y = (y * (2 - (x & 0xf) * y)) & 0xf; // y == 1/x mod 2^4
575 + y = (y * (2 - (x & 0xff) * y)) & 0xff; // y == 1/x mod 2^8
576 + y = (y * (2 - (((x & 0xffff) * y) & 0xffff))) & 0xffff; // y == 1/x mod 2^16
577 + // last step - calculate inverse mod DV directly;
578 + // assumes 16 < DB <= 32 and assumes ability to handle 48-bit ints
579 + y = (y * (2 - x * y % this.DV)) % this.DV; // y == 1/x mod 2^dbits
580 + // we really want the negative inverse, and -DV < y < DV
581 + return (y > 0) ? this.DV - y : -y;
582 +}
583 +
584 +// Montgomery reduction
585 +function Montgomery(m) {
586 + this.m = m;
587 + this.mp = m.invDigit();
588 + this.mpl = this.mp & 0x7fff;
589 + this.mph = this.mp >> 15;
590 + this.um = (1 << (m.DB - 15)) - 1;
591 + this.mt2 = 2 * m.t;
592 +}
593 +
594 +// xR mod m
595 +function montConvert(x) {
596 + var r = nbi();
597 + x.abs().dlShiftTo(this.m.t, r);
598 + r.divRemTo(this.m, null, r);
599 + if (x.s < 0 && r.compareTo(BigInteger.ZERO) > 0) this.m.subTo(r, r);
600 + return r;
601 +}
602 +
603 +// x/R mod m
604 +function montRevert(x) {
605 + var r = nbi();
606 + x.copyTo(r);
607 + this.reduce(r);
608 + return r;
609 +}
610 +
611 +// x = x/R mod m (HAC 14.32)
612 +function montReduce(x) {
613 + while (x.t <= this.mt2) // pad x so am has enough room later
614 + x[x.t++] = 0;
615 + for (var i = 0; i < this.m.t; ++i) {
616 + // faster way of calculating u0 = x[i]*mp mod DV
617 + var j = x[i] & 0x7fff;
618 + var u0 = (j * this.mpl + (((j * this.mph + (x[i] >> 15) * this.mpl) & this.um) << 15)) & x.DM;
619 + // use am to combine the multiply-shift-add into one call
620 + j = i + this.m.t;
621 + x[j] += this.m.am(0, u0, x, i, 0, this.m.t);
622 + // propagate carry
623 + while (x[j] >= x.DV) {
624 + x[j] -= x.DV;
625 + x[++j]++;
626 + }
627 + }
628 + x.clamp();
629 + x.drShiftTo(this.m.t, x);
630 + if (x.compareTo(this.m) >= 0) x.subTo(this.m, x);
631 +}
632 +
633 +// r = "x^2/R mod m"; x != r
634 +function montSqrTo(x, r) {
635 + x.squareTo(r);
636 + this.reduce(r);
637 +}
638 +
639 +// r = "xy/R mod m"; x,y != r
640 +function montMulTo(x, y, r) {
641 + x.multiplyTo(y, r);
642 + this.reduce(r);
643 +}
644 +
645 +Montgomery.prototype.convert = montConvert;
646 +Montgomery.prototype.revert = montRevert;
647 +Montgomery.prototype.reduce = montReduce;
648 +Montgomery.prototype.mulTo = montMulTo;
649 +Montgomery.prototype.sqrTo = montSqrTo;
650 +
651 +// (protected) true iff this is even
652 +function bnpIsEven() {
653 + return ((this.t > 0) ? (this[0] & 1) : this.s) === 0;
654 +}
655 +
656 +// (protected) this^e, e < 2^32, doing sqr and mul with "r" (HAC 14.79)
657 +function bnpExp(e, z) {
658 + if (e > 0xffffffff || e < 1) return BigInteger.ONE;
659 + var r = nbi(), r2 = nbi(), g = z.convert(this), i = nbits(e) - 1;
660 + g.copyTo(r);
661 + while (--i >= 0) {
662 + z.sqrTo(r, r2);
663 + if ((e & (1 << i)) > 0) z.mulTo(r2, g, r);
664 + else {
665 + var t = r;
666 + r = r2;
667 + r2 = t;
668 + }
669 + }
670 + return z.revert(r);
671 +}
672 +
673 +// (public) this^e % m, 0 <= e < 2^32
674 +function bnModPowInt(e, m) {
675 + var z;
676 + if (e < 256 || m.isEven()) z = new Classic(m); else z = new Montgomery(m);
677 + return this.exp(e, z);
678 +}
679 +
680 +// Copyright (c) 2005-2009 Tom Wu
681 +// All Rights Reserved.
682 +// See "LICENSE" for details.
683 +
684 +// Extended JavaScript BN functions, required for RSA private ops.
685 +
686 +// Version 1.1: new BigInteger("0", 10) returns "proper" zero
687 +// Version 1.2: square() API, isProbablePrime fix
688 +
689 +//(public)
690 +function bnClone() {
691 + var r = nbi();
692 + this.copyTo(r);
693 + return r;
694 +}
695 +
696 +//(public) return value as integer
697 +function bnIntValue() {
698 + if (this.s < 0) {
699 + if (this.t == 1) return this[0] - this.DV;
700 + else if (this.t === 0) return -1;
701 + }
702 + else if (this.t == 1) return this[0];
703 + else if (this.t === 0) return 0;
704 +// assumes 16 < DB < 32
705 + return ((this[1] & ((1 << (32 - this.DB)) - 1)) << this.DB) | this[0];
706 +}
707 +
708 +//(public) return value as byte
709 +function bnByteValue() {
710 + return (this.t == 0) ? this.s : (this[0] << 24) >> 24;
711 +}
712 +
713 +//(public) return value as short (assumes DB>=16)
714 +function bnShortValue() {
715 + return (this.t == 0) ? this.s : (this[0] << 16) >> 16;
716 +}
717 +
718 +//(protected) return x s.t. r^x < DV
719 +function bnpChunkSize(r) {
720 + return Math.floor(Math.LN2 * this.DB / Math.log(r));
721 +}
722 +
723 +//(public) 0 if this === 0, 1 if this > 0
724 +function bnSigNum() {
725 + if (this.s < 0) return -1;
726 + else if (this.t <= 0 || (this.t == 1 && this[0] <= 0)) return 0;
727 + else return 1;
728 +}
729 +
730 +//(protected) convert to radix string
731 +function bnpToRadix(b) {
732 + if (b == null) b = 10;
733 + if (this.signum() === 0 || b < 2 || b > 36) return "0";
734 + var cs = this.chunkSize(b);
735 + var a = Math.pow(b, cs);
736 + var d = nbv(a), y = nbi(), z = nbi(), r = "";
737 + this.divRemTo(d, y, z);
738 + while (y.signum() > 0) {
739 + r = (a + z.intValue()).toString(b).substr(1) + r;
740 + y.divRemTo(d, y, z);
741 + }
742 + return z.intValue().toString(b) + r;
743 +}
744 +
745 +//(protected) convert from radix string
746 +function bnpFromRadix(s, b) {
747 + this.fromInt(0);
748 + if (b == null) b = 10;
749 + var cs = this.chunkSize(b);
750 + var d = Math.pow(b, cs), mi = false, j = 0, w = 0;
751 + for (var i = 0; i < s.length; ++i) {
752 + var x = intAt(s, i);
753 + if (x < 0) {
754 + if (s.charAt(i) == "-" && this.signum() === 0) mi = true;
755 + continue;
756 + }
757 + w = b * w + x;
758 + if (++j >= cs) {
759 + this.dMultiply(d);
760 + this.dAddOffset(w, 0);
761 + j = 0;
762 + w = 0;
763 + }
764 + }
765 + if (j > 0) {
766 + this.dMultiply(Math.pow(b, j));
767 + this.dAddOffset(w, 0);
768 + }
769 + if (mi) BigInteger.ZERO.subTo(this, this);
770 +}
771 +
772 +//(protected) alternate constructor
773 +function bnpFromNumber(a, b) {
774 + if ("number" == typeof b) {
775 + // new BigInteger(int,int,RNG)
776 + if (a < 2) this.fromInt(1);
777 + else {
778 + this.fromNumber(a);
779 + if (!this.testBit(a - 1)) // force MSB set
780 + this.bitwiseTo(BigInteger.ONE.shiftLeft(a - 1), op_or, this);
781 + if (this.isEven()) this.dAddOffset(1, 0); // force odd
782 + while (!this.isProbablePrime(b)) {
783 + this.dAddOffset(2, 0);
784 + if (this.bitLength() > a) this.subTo(BigInteger.ONE.shiftLeft(a - 1), this);
785 + }
786 + }
787 + } else {
788 + // new BigInteger(int,RNG)
789 + var x = crypt.randomBytes((a >> 3) + 1)
790 + var t = a & 7;
791 +
792 + if (t > 0)
793 + x[0] &= ((1 << t) - 1);
794 + else
795 + x[0] = 0;
796 +
797 + this.fromByteArray(x);
798 + }
799 +}
800 +
801 +//(public) convert to bigendian byte array
802 +function bnToByteArray() {
803 + var i = this.t, r = new Array();
804 + r[0] = this.s;
805 + var p = this.DB - (i * this.DB) % 8, d, k = 0;
806 + if (i-- > 0) {
807 + if (p < this.DB && (d = this[i] >> p) != (this.s & this.DM) >> p)
808 + r[k++] = d | (this.s << (this.DB - p));
809 + while (i >= 0) {
810 + if (p < 8) {
811 + d = (this[i] & ((1 << p) - 1)) << (8 - p);
812 + d |= this[--i] >> (p += this.DB - 8);
813 + }
814 + else {
815 + d = (this[i] >> (p -= 8)) & 0xff;
816 + if (p <= 0) {
817 + p += this.DB;
818 + --i;
819 + }
820 + }
821 + if ((d & 0x80) != 0) d |= -256;
822 + if (k === 0 && (this.s & 0x80) != (d & 0x80)) ++k;
823 + if (k > 0 || d != this.s) r[k++] = d;
824 + }
825 + }
826 + return r;
827 +}
828 +
829 +/**
830 + * return Buffer object
831 + * @param trim {boolean} slice buffer if first element == 0
832 + * @returns {Buffer}
833 + */
834 +function bnToBuffer(trimOrSize) {
835 + var res = Buffer.from(this.toByteArray());
836 + if (trimOrSize === true && res[0] === 0) {
837 + res = res.slice(1);
838 + } else if (isNumber(trimOrSize)) {
839 + if (res.length > trimOrSize) {
840 + for (var i = 0; i < res.length - trimOrSize; i++) {
841 + if (res[i] !== 0) {
842 + return null;
843 + }
844 + }
845 + return res.slice(res.length - trimOrSize);
846 + } else if (res.length < trimOrSize) {
847 + var padded = Buffer.alloc(trimOrSize);
848 + padded.fill(0, 0, trimOrSize - res.length);
849 + res.copy(padded, trimOrSize - res.length);
850 + return padded;
851 + }
852 + }
853 + return res;
854 +}
855 +
856 +function bnEquals(a) {
857 + return (this.compareTo(a) == 0);
858 +}
859 +function bnMin(a) {
860 + return (this.compareTo(a) < 0) ? this : a;
861 +}
862 +function bnMax(a) {
863 + return (this.compareTo(a) > 0) ? this : a;
864 +}
865 +
866 +//(protected) r = this op a (bitwise)
867 +function bnpBitwiseTo(a, op, r) {
868 + var i, f, m = Math.min(a.t, this.t);
869 + for (i = 0; i < m; ++i) r[i] = op(this[i], a[i]);
870 + if (a.t < this.t) {
871 + f = a.s & this.DM;
872 + for (i = m; i < this.t; ++i) r[i] = op(this[i], f);
873 + r.t = this.t;
874 + }
875 + else {
876 + f = this.s & this.DM;
877 + for (i = m; i < a.t; ++i) r[i] = op(f, a[i]);
878 + r.t = a.t;
879 + }
880 + r.s = op(this.s, a.s);
881 + r.clamp();
882 +}
883 +
884 +//(public) this & a
885 +function op_and(x, y) {
886 + return x & y;
887 +}
888 +function bnAnd(a) {
889 + var r = nbi();
890 + this.bitwiseTo(a, op_and, r);
891 + return r;
892 +}
893 +
894 +//(public) this | a
895 +function op_or(x, y) {
896 + return x | y;
897 +}
898 +function bnOr(a) {
899 + var r = nbi();
900 + this.bitwiseTo(a, op_or, r);
901 + return r;
902 +}
903 +
904 +//(public) this ^ a
905 +function op_xor(x, y) {
906 + return x ^ y;
907 +}
908 +function bnXor(a) {
909 + var r = nbi();
910 + this.bitwiseTo(a, op_xor, r);
911 + return r;
912 +}
913 +
914 +//(public) this & ~a
915 +function op_andnot(x, y) {
916 + return x & ~y;
917 +}
918 +function bnAndNot(a) {
919 + var r = nbi();
920 + this.bitwiseTo(a, op_andnot, r);
921 + return r;
922 +}
923 +
924 +//(public) ~this
925 +function bnNot() {
926 + var r = nbi();
927 + for (var i = 0; i < this.t; ++i) r[i] = this.DM & ~this[i];
928 + r.t = this.t;
929 + r.s = ~this.s;
930 + return r;
931 +}
932 +
933 +//(public) this << n
934 +function bnShiftLeft(n) {
935 + var r = nbi();
936 + if (n < 0) this.rShiftTo(-n, r); else this.lShiftTo(n, r);
937 + return r;
938 +}
939 +
940 +//(public) this >> n
941 +function bnShiftRight(n) {
942 + var r = nbi();
943 + if (n < 0) this.lShiftTo(-n, r); else this.rShiftTo(n, r);
944 + return r;
945 +}
946 +
947 +//return index of lowest 1-bit in x, x < 2^31
948 +function lbit(x) {
949 + if (x === 0) return -1;
950 + var r = 0;
951 + if ((x & 0xffff) === 0) {
952 + x >>= 16;
953 + r += 16;
954 + }
955 + if ((x & 0xff) === 0) {
956 + x >>= 8;
957 + r += 8;
958 + }
959 + if ((x & 0xf) === 0) {
960 + x >>= 4;
961 + r += 4;
962 + }
963 + if ((x & 3) === 0) {
964 + x >>= 2;
965 + r += 2;
966 + }
967 + if ((x & 1) === 0) ++r;
968 + return r;
969 +}
970 +
971 +//(public) returns index of lowest 1-bit (or -1 if none)
972 +function bnGetLowestSetBit() {
973 + for (var i = 0; i < this.t; ++i)
974 + if (this[i] != 0) return i * this.DB + lbit(this[i]);
975 + if (this.s < 0) return this.t * this.DB;
976 + return -1;
977 +}
978 +
979 +//return number of 1 bits in x
980 +function cbit(x) {
981 + var r = 0;
982 + while (x != 0) {
983 + x &= x - 1;
984 + ++r;
985 + }
986 + return r;
987 +}
988 +
989 +//(public) return number of set bits
990 +function bnBitCount() {
991 + var r = 0, x = this.s & this.DM;
992 + for (var i = 0; i < this.t; ++i) r += cbit(this[i] ^ x);
993 + return r;
994 +}
995 +
996 +//(public) true iff nth bit is set
997 +function bnTestBit(n) {
998 + var j = Math.floor(n / this.DB);
999 + if (j >= this.t) return (this.s != 0);
1000 + return ((this[j] & (1 << (n % this.DB))) != 0);
1001 +}
1002 +
1003 +//(protected) this op (1<<n)
1004 +function bnpChangeBit(n, op) {
1005 + var r = BigInteger.ONE.shiftLeft(n);
1006 + this.bitwiseTo(r, op, r);
1007 + return r;
1008 +}
1009 +
1010 +//(public) this | (1<<n)
1011 +function bnSetBit(n) {
1012 + return this.changeBit(n, op_or);
1013 +}
1014 +
1015 +//(public) this & ~(1<<n)
1016 +function bnClearBit(n) {
1017 + return this.changeBit(n, op_andnot);
1018 +}
1019 +
1020 +//(public) this ^ (1<<n)
1021 +function bnFlipBit(n) {
1022 + return this.changeBit(n, op_xor);
1023 +}
1024 +
1025 +//(protected) r = this + a
1026 +function bnpAddTo(a, r) {
1027 + var i = 0, c = 0, m = Math.min(a.t, this.t);
1028 + while (i < m) {
1029 + c += this[i] + a[i];
1030 + r[i++] = c & this.DM;
1031 + c >>= this.DB;
1032 + }
1033 + if (a.t < this.t) {
1034 + c += a.s;
1035 + while (i < this.t) {
1036 + c += this[i];
1037 + r[i++] = c & this.DM;
1038 + c >>= this.DB;
1039 + }
1040 + c += this.s;
1041 + }
1042 + else {
1043 + c += this.s;
1044 + while (i < a.t) {
1045 + c += a[i];
1046 + r[i++] = c & this.DM;
1047 + c >>= this.DB;
1048 + }
1049 + c += a.s;
1050 + }
1051 + r.s = (c < 0) ? -1 : 0;
1052 + if (c > 0) r[i++] = c;
1053 + else if (c < -1) r[i++] = this.DV + c;
1054 + r.t = i;
1055 + r.clamp();
1056 +}
1057 +
1058 +//(public) this + a
1059 +function bnAdd(a) {
1060 + var r = nbi();
1061 + this.addTo(a, r);
1062 + return r;
1063 +}
1064 +
1065 +//(public) this - a
1066 +function bnSubtract(a) {
1067 + var r = nbi();
1068 + this.subTo(a, r);
1069 + return r;
1070 +}
1071 +
1072 +//(public) this * a
1073 +function bnMultiply(a) {
1074 + var r = nbi();
1075 + this.multiplyTo(a, r);
1076 + return r;
1077 +}
1078 +
1079 +// (public) this^2
1080 +function bnSquare() {
1081 + var r = nbi();
1082 + this.squareTo(r);
1083 + return r;
1084 +}
1085 +
1086 +//(public) this / a
1087 +function bnDivide(a) {
1088 + var r = nbi();
1089 + this.divRemTo(a, r, null);
1090 + return r;
1091 +}
1092 +
1093 +//(public) this % a
1094 +function bnRemainder(a) {
1095 + var r = nbi();
1096 + this.divRemTo(a, null, r);
1097 + return r;
1098 +}
1099 +
1100 +//(public) [this/a,this%a]
1101 +function bnDivideAndRemainder(a) {
1102 + var q = nbi(), r = nbi();
1103 + this.divRemTo(a, q, r);
1104 + return new Array(q, r);
1105 +}
1106 +
1107 +//(protected) this *= n, this >= 0, 1 < n < DV
1108 +function bnpDMultiply(n) {
1109 + this[this.t] = this.am(0, n - 1, this, 0, 0, this.t);
1110 + ++this.t;
1111 + this.clamp();
1112 +}
1113 +
1114 +//(protected) this += n << w words, this >= 0
1115 +function bnpDAddOffset(n, w) {
1116 + if (n === 0) return;
1117 + while (this.t <= w) this[this.t++] = 0;
1118 + this[w] += n;
1119 + while (this[w] >= this.DV) {
1120 + this[w] -= this.DV;
1121 + if (++w >= this.t) this[this.t++] = 0;
1122 + ++this[w];
1123 + }
1124 +}
1125 +
1126 +//A "null" reducer
1127 +function NullExp() {
1128 +}
1129 +function nNop(x) {
1130 + return x;
1131 +}
1132 +function nMulTo(x, y, r) {
1133 + x.multiplyTo(y, r);
1134 +}
1135 +function nSqrTo(x, r) {
1136 + x.squareTo(r);
1137 +}
1138 +
1139 +NullExp.prototype.convert = nNop;
1140 +NullExp.prototype.revert = nNop;
1141 +NullExp.prototype.mulTo = nMulTo;
1142 +NullExp.prototype.sqrTo = nSqrTo;
1143 +
1144 +//(public) this^e
1145 +function bnPow(e) {
1146 + return this.exp(e, new NullExp());
1147 +}
1148 +
1149 +//(protected) r = lower n words of "this * a", a.t <= n
1150 +//"this" should be the larger one if appropriate.
1151 +function bnpMultiplyLowerTo(a, n, r) {
1152 + var i = Math.min(this.t + a.t, n);
1153 + r.s = 0; // assumes a,this >= 0
1154 + r.t = i;
1155 + while (i > 0) r[--i] = 0;
1156 + var j;
1157 + for (j = r.t - this.t; i < j; ++i) r[i + this.t] = this.am(0, a[i], r, i, 0, this.t);
1158 + for (j = Math.min(a.t, n); i < j; ++i) this.am(0, a[i], r, i, 0, n - i);
1159 + r.clamp();
1160 +}
1161 +
1162 +//(protected) r = "this * a" without lower n words, n > 0
1163 +//"this" should be the larger one if appropriate.
1164 +function bnpMultiplyUpperTo(a, n, r) {
1165 + --n;
1166 + var i = r.t = this.t + a.t - n;
1167 + r.s = 0; // assumes a,this >= 0
1168 + while (--i >= 0) r[i] = 0;
1169 + for (i = Math.max(n - this.t, 0); i < a.t; ++i)
1170 + r[this.t + i - n] = this.am(n - i, a[i], r, 0, 0, this.t + i - n);
1171 + r.clamp();
1172 + r.drShiftTo(1, r);
1173 +}
1174 +
1175 +//Barrett modular reduction
1176 +function Barrett(m) {
1177 +// setup Barrett
1178 + this.r2 = nbi();
1179 + this.q3 = nbi();
1180 + BigInteger.ONE.dlShiftTo(2 * m.t, this.r2);
1181 + this.mu = this.r2.divide(m);
1182 + this.m = m;
1183 +}
1184 +
1185 +function barrettConvert(x) {
1186 + if (x.s < 0 || x.t > 2 * this.m.t) return x.mod(this.m);
1187 + else if (x.compareTo(this.m) < 0) return x;
1188 + else {
1189 + var r = nbi();
1190 + x.copyTo(r);
1191 + this.reduce(r);
1192 + return r;
1193 + }
1194 +}
1195 +
1196 +function barrettRevert(x) {
1197 + return x;
1198 +}
1199 +
1200 +//x = x mod m (HAC 14.42)
1201 +function barrettReduce(x) {
1202 + x.drShiftTo(this.m.t - 1, this.r2);
1203 + if (x.t > this.m.t + 1) {
1204 + x.t = this.m.t + 1;
1205 + x.clamp();
1206 + }
1207 + this.mu.multiplyUpperTo(this.r2, this.m.t + 1, this.q3);
1208 + this.m.multiplyLowerTo(this.q3, this.m.t + 1, this.r2);
1209 + while (x.compareTo(this.r2) < 0) x.dAddOffset(1, this.m.t + 1);
1210 + x.subTo(this.r2, x);
1211 + while (x.compareTo(this.m) >= 0) x.subTo(this.m, x);
1212 +}
1213 +
1214 +//r = x^2 mod m; x != r
1215 +function barrettSqrTo(x, r) {
1216 + x.squareTo(r);
1217 + this.reduce(r);
1218 +}
1219 +
1220 +//r = x*y mod m; x,y != r
1221 +function barrettMulTo(x, y, r) {
1222 + x.multiplyTo(y, r);
1223 + this.reduce(r);
1224 +}
1225 +
1226 +Barrett.prototype.convert = barrettConvert;
1227 +Barrett.prototype.revert = barrettRevert;
1228 +Barrett.prototype.reduce = barrettReduce;
1229 +Barrett.prototype.mulTo = barrettMulTo;
1230 +Barrett.prototype.sqrTo = barrettSqrTo;
1231 +
1232 +//(public) this^e % m (HAC 14.85)
1233 +function bnModPow(e, m) {
1234 + var i = e.bitLength(), k, r = nbv(1), z;
1235 + if (i <= 0) return r;
1236 + else if (i < 18) k = 1;
1237 + else if (i < 48) k = 3;
1238 + else if (i < 144) k = 4;
1239 + else if (i < 768) k = 5;
1240 + else k = 6;
1241 + if (i < 8)
1242 + z = new Classic(m);
1243 + else if (m.isEven())
1244 + z = new Barrett(m);
1245 + else
1246 + z = new Montgomery(m);
1247 +
1248 +// precomputation
1249 + var g = new Array(), n = 3, k1 = k - 1, km = (1 << k) - 1;
1250 + g[1] = z.convert(this);
1251 + if (k > 1) {
1252 + var g2 = nbi();
1253 + z.sqrTo(g[1], g2);
1254 + while (n <= km) {
1255 + g[n] = nbi();
1256 + z.mulTo(g2, g[n - 2], g[n]);
1257 + n += 2;
1258 + }
1259 + }
1260 +
1261 + var j = e.t - 1, w, is1 = true, r2 = nbi(), t;
1262 + i = nbits(e[j]) - 1;
1263 + while (j >= 0) {
1264 + if (i >= k1) w = (e[j] >> (i - k1)) & km;
1265 + else {
1266 + w = (e[j] & ((1 << (i + 1)) - 1)) << (k1 - i);
1267 + if (j > 0) w |= e[j - 1] >> (this.DB + i - k1);
1268 + }
1269 +
1270 + n = k;
1271 + while ((w & 1) === 0) {
1272 + w >>= 1;
1273 + --n;
1274 + }
1275 + if ((i -= n) < 0) {
1276 + i += this.DB;
1277 + --j;
1278 + }
1279 + if (is1) { // ret == 1, don't bother squaring or multiplying it
1280 + g[w].copyTo(r);
1281 + is1 = false;
1282 + }
1283 + else {
1284 + while (n > 1) {
1285 + z.sqrTo(r, r2);
1286 + z.sqrTo(r2, r);
1287 + n -= 2;
1288 + }
1289 + if (n > 0) z.sqrTo(r, r2); else {
1290 + t = r;
1291 + r = r2;
1292 + r2 = t;
1293 + }
1294 + z.mulTo(r2, g[w], r);
1295 + }
1296 +
1297 + while (j >= 0 && (e[j] & (1 << i)) === 0) {
1298 + z.sqrTo(r, r2);
1299 + t = r;
1300 + r = r2;
1301 + r2 = t;
1302 + if (--i < 0) {
1303 + i = this.DB - 1;
1304 + --j;
1305 + }
1306 + }
1307 + }
1308 + return z.revert(r);
1309 +}
1310 +
1311 +//(public) gcd(this,a) (HAC 14.54)
1312 +function bnGCD(a) {
1313 + var x = (this.s < 0) ? this.negate() : this.clone();
1314 + var y = (a.s < 0) ? a.negate() : a.clone();
1315 + if (x.compareTo(y) < 0) {
1316 + var t = x;
1317 + x = y;
1318 + y = t;
1319 + }
1320 + var i = x.getLowestSetBit(), g = y.getLowestSetBit();
1321 + if (g < 0) return x;
1322 + if (i < g) g = i;
1323 + if (g > 0) {
1324 + x.rShiftTo(g, x);
1325 + y.rShiftTo(g, y);
1326 + }
1327 + while (x.signum() > 0) {
1328 + if ((i = x.getLowestSetBit()) > 0) x.rShiftTo(i, x);
1329 + if ((i = y.getLowestSetBit()) > 0) y.rShiftTo(i, y);
1330 + if (x.compareTo(y) >= 0) {
1331 + x.subTo(y, x);
1332 + x.rShiftTo(1, x);
1333 + }
1334 + else {
1335 + y.subTo(x, y);
1336 + y.rShiftTo(1, y);
1337 + }
1338 + }
1339 + if (g > 0) y.lShiftTo(g, y);
1340 + return y;
1341 +}
1342 +
1343 +//(protected) this % n, n < 2^26
1344 +function bnpModInt(n) {
1345 + if (n <= 0) return 0;
1346 + var d = this.DV % n, r = (this.s < 0) ? n - 1 : 0;
1347 + if (this.t > 0)
1348 + if (d === 0) r = this[0] % n;
1349 + else for (var i = this.t - 1; i >= 0; --i) r = (d * r + this[i]) % n;
1350 + return r;
1351 +}
1352 +
1353 +//(public) 1/this % m (HAC 14.61)
1354 +function bnModInverse(m) {
1355 + var ac = m.isEven();
1356 + if ((this.isEven() && ac) || m.signum() === 0) return BigInteger.ZERO;
1357 + var u = m.clone(), v = this.clone();
1358 + var a = nbv(1), b = nbv(0), c = nbv(0), d = nbv(1);
1359 + while (u.signum() != 0) {
1360 + while (u.isEven()) {
1361 + u.rShiftTo(1, u);
1362 + if (ac) {
1363 + if (!a.isEven() || !b.isEven()) {
1364 + a.addTo(this, a);
1365 + b.subTo(m, b);
1366 + }
1367 + a.rShiftTo(1, a);
1368 + }
1369 + else if (!b.isEven()) b.subTo(m, b);
1370 + b.rShiftTo(1, b);
1371 + }
1372 + while (v.isEven()) {
1373 + v.rShiftTo(1, v);
1374 + if (ac) {
1375 + if (!c.isEven() || !d.isEven()) {
1376 + c.addTo(this, c);
1377 + d.subTo(m, d);
1378 + }
1379 + c.rShiftTo(1, c);
1380 + }
1381 + else if (!d.isEven()) d.subTo(m, d);
1382 + d.rShiftTo(1, d);
1383 + }
1384 + if (u.compareTo(v) >= 0) {
1385 + u.subTo(v, u);
1386 + if (ac) a.subTo(c, a);
1387 + b.subTo(d, b);
1388 + }
1389 + else {
1390 + v.subTo(u, v);
1391 + if (ac) c.subTo(a, c);
1392 + d.subTo(b, d);
1393 + }
1394 + }
1395 + if (v.compareTo(BigInteger.ONE) != 0) return BigInteger.ZERO;
1396 + if (d.compareTo(m) >= 0) return d.subtract(m);
1397 + if (d.signum() < 0) d.addTo(m, d); else return d;
1398 + if (d.signum() < 0) return d.add(m); else return d;
1399 +}
1400 +
1401 +var lowprimes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997];
1402 +var lplim = (1 << 26) / lowprimes[lowprimes.length - 1];
1403 +
1404 +//(public) test primality with certainty >= 1-.5^t
1405 +function bnIsProbablePrime(t) {
1406 + var i, x = this.abs();
1407 + if (x.t == 1 && x[0] <= lowprimes[lowprimes.length - 1]) {
1408 + for (i = 0; i < lowprimes.length; ++i)
1409 + if (x[0] == lowprimes[i]) return true;
1410 + return false;
1411 + }
1412 + if (x.isEven()) return false;
1413 + i = 1;
1414 + while (i < lowprimes.length) {
1415 + var m = lowprimes[i], j = i + 1;
1416 + while (j < lowprimes.length && m < lplim) m *= lowprimes[j++];
1417 + m = x.modInt(m);
1418 + while (i < j) if (m % lowprimes[i++] === 0) return false;
1419 + }
1420 + return x.millerRabin(t);
1421 +}
1422 +
1423 +//(protected) true if probably prime (HAC 4.24, Miller-Rabin)
1424 +function bnpMillerRabin(t) {
1425 + var n1 = this.subtract(BigInteger.ONE);
1426 + var k = n1.getLowestSetBit();
1427 + if (k <= 0) return false;
1428 + var r = n1.shiftRight(k);
1429 + t = (t + 1) >> 1;
1430 + if (t > lowprimes.length) t = lowprimes.length;
1431 + var a = nbi();
1432 + for (var i = 0; i < t; ++i) {
1433 + //Pick bases at random, instead of starting at 2
1434 + a.fromInt(lowprimes[Math.floor(Math.random() * lowprimes.length)]);
1435 + var y = a.modPow(r, this);
1436 + if (y.compareTo(BigInteger.ONE) != 0 && y.compareTo(n1) != 0) {
1437 + var j = 1;
1438 + while (j++ < k && y.compareTo(n1) != 0) {
1439 + y = y.modPowInt(2, this);
1440 + if (y.compareTo(BigInteger.ONE) === 0) return false;
1441 + }
1442 + if (y.compareTo(n1) != 0) return false;
1443 + }
1444 + }
1445 + return true;
1446 +}
1447 +
1448 +// protected
1449 +BigInteger.prototype.copyTo = bnpCopyTo;
1450 +BigInteger.prototype.fromInt = bnpFromInt;
1451 +BigInteger.prototype.fromString = bnpFromString;
1452 +BigInteger.prototype.fromByteArray = bnpFromByteArray;
1453 +BigInteger.prototype.fromBuffer = bnpFromBuffer;
1454 +BigInteger.prototype.clamp = bnpClamp;
1455 +BigInteger.prototype.dlShiftTo = bnpDLShiftTo;
1456 +BigInteger.prototype.drShiftTo = bnpDRShiftTo;
1457 +BigInteger.prototype.lShiftTo = bnpLShiftTo;
1458 +BigInteger.prototype.rShiftTo = bnpRShiftTo;
1459 +BigInteger.prototype.subTo = bnpSubTo;
1460 +BigInteger.prototype.multiplyTo = bnpMultiplyTo;
1461 +BigInteger.prototype.squareTo = bnpSquareTo;
1462 +BigInteger.prototype.divRemTo = bnpDivRemTo;
1463 +BigInteger.prototype.invDigit = bnpInvDigit;
1464 +BigInteger.prototype.isEven = bnpIsEven;
1465 +BigInteger.prototype.exp = bnpExp;
1466 +
1467 +BigInteger.prototype.chunkSize = bnpChunkSize;
1468 +BigInteger.prototype.toRadix = bnpToRadix;
1469 +BigInteger.prototype.fromRadix = bnpFromRadix;
1470 +BigInteger.prototype.fromNumber = bnpFromNumber;
1471 +BigInteger.prototype.bitwiseTo = bnpBitwiseTo;
1472 +BigInteger.prototype.changeBit = bnpChangeBit;
1473 +BigInteger.prototype.addTo = bnpAddTo;
1474 +BigInteger.prototype.dMultiply = bnpDMultiply;
1475 +BigInteger.prototype.dAddOffset = bnpDAddOffset;
1476 +BigInteger.prototype.multiplyLowerTo = bnpMultiplyLowerTo;
1477 +BigInteger.prototype.multiplyUpperTo = bnpMultiplyUpperTo;
1478 +BigInteger.prototype.modInt = bnpModInt;
1479 +BigInteger.prototype.millerRabin = bnpMillerRabin;
1480 +
1481 +
1482 +// public
1483 +BigInteger.prototype.toString = bnToString;
1484 +BigInteger.prototype.negate = bnNegate;
1485 +BigInteger.prototype.abs = bnAbs;
1486 +BigInteger.prototype.compareTo = bnCompareTo;
1487 +BigInteger.prototype.bitLength = bnBitLength;
1488 +BigInteger.prototype.mod = bnMod;
1489 +BigInteger.prototype.modPowInt = bnModPowInt;
1490 +
1491 +BigInteger.prototype.clone = bnClone;
1492 +BigInteger.prototype.intValue = bnIntValue;
1493 +BigInteger.prototype.byteValue = bnByteValue;
1494 +BigInteger.prototype.shortValue = bnShortValue;
1495 +BigInteger.prototype.signum = bnSigNum;
1496 +BigInteger.prototype.toByteArray = bnToByteArray;
1497 +BigInteger.prototype.toBuffer = bnToBuffer;
1498 +BigInteger.prototype.equals = bnEquals;
1499 +BigInteger.prototype.min = bnMin;
1500 +BigInteger.prototype.max = bnMax;
1501 +BigInteger.prototype.and = bnAnd;
1502 +BigInteger.prototype.or = bnOr;
1503 +BigInteger.prototype.xor = bnXor;
1504 +BigInteger.prototype.andNot = bnAndNot;
1505 +BigInteger.prototype.not = bnNot;
1506 +BigInteger.prototype.shiftLeft = bnShiftLeft;
1507 +BigInteger.prototype.shiftRight = bnShiftRight;
1508 +BigInteger.prototype.getLowestSetBit = bnGetLowestSetBit;
1509 +BigInteger.prototype.bitCount = bnBitCount;
1510 +BigInteger.prototype.testBit = bnTestBit;
1511 +BigInteger.prototype.setBit = bnSetBit;
1512 +BigInteger.prototype.clearBit = bnClearBit;
1513 +BigInteger.prototype.flipBit = bnFlipBit;
1514 +BigInteger.prototype.add = bnAdd;
1515 +BigInteger.prototype.subtract = bnSubtract;
1516 +BigInteger.prototype.multiply = bnMultiply;
1517 +BigInteger.prototype.divide = bnDivide;
1518 +BigInteger.prototype.remainder = bnRemainder;
1519 +BigInteger.prototype.divideAndRemainder = bnDivideAndRemainder;
1520 +BigInteger.prototype.modPow = bnModPow;
1521 +BigInteger.prototype.modInverse = bnModInverse;
1522 +BigInteger.prototype.pow = bnPow;
1523 +BigInteger.prototype.gcd = bnGCD;
1524 +BigInteger.prototype.isProbablePrime = bnIsProbablePrime;
1525 +BigInteger.int2char = int2char;
1526 +
1527 +// "constants"
1528 +BigInteger.ZERO = nbv(0);
1529 +BigInteger.ONE = nbv(1);
1530 +
1531 +// JSBN-specific extension
1532 +BigInteger.prototype.square = bnSquare;
1533 +
1534 +//BigInteger interfaces not implemented in jsbn:
1535 +
1536 +//BigInteger(int signum, byte[] magnitude)
1537 +//double doubleValue()
1538 +//float floatValue()
1539 +//int hashCode()
1540 +//long longValue()
1541 +//static BigInteger valueOf(long val)
1542 +
1543 +module.exports = BigInteger;
\ No newline at end of file
rdp/security/rsa.js new
+43
@@ -0,0 +1,43 @@
1 +/*
2 + * Copyright (c) 2014-2015 Sylvain Peyrefitte
3 + *
4 + * This file is part of node-rdpjs.
5 + *
6 + * node-rdpjs is free software: you can redistribute it and/or modify
7 + * it under the terms of the GNU General Public License as published by
8 + * the Free Software Foundation, either version 3 of the License, or
9 + * (at your option) any later version.
10 + *
11 + * This program is distributed in the hope that it will be useful,
12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 + * GNU General Public License for more details.
15 + *
16 + * You should have received a copy of the GNU General Public License
17 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 + */
19 +
20 +var BigInteger = require('./jsbn');
21 +
22 +/**
23 + * @param modulus {Buffer}
24 + * @param pubExp {integer}
25 + */
26 +function publicKey(modulus, pubExp) {
27 + return {
28 + n : modulus,
29 + e : pubExp
30 + }
31 +}
32 +
33 +function encrypt(data, publicKey) {
34 + return new BigInteger(data).modPowInt(publicKey.e, new BigInteger(publicKey.n)).toBuffer();
35 +}
36 +
37 +/**
38 + * Module Export
39 + */
40 +module.exports = {
41 + publicKey : publicKey,
42 + encrypt : encrypt
43 +};
\ No newline at end of file
rdp/security/x509.js new
+216
@@ -0,0 +1,216 @@
1 +/*
2 + * Copyright (c) 2014-2015 Sylvain Peyrefitte
3 + *
4 + * This file is part of node-rdpjs.
5 + *
6 + * node-rdpjs is free software: you can redistribute it and/or modify
7 + * it under the terms of the GNU General Public License as published by
8 + * the Free Software Foundation, either version 3 of the License, or
9 + * (at your option) any later version.
10 + *
11 + * This program is distributed in the hope that it will be useful,
12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 + * GNU General Public License for more details.
15 + *
16 + * You should have received a copy of the GNU General Public License
17 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 + */
19 +
20 +// https://tools.ietf.org/html/rfc5280
21 +
22 +var asn1 = require('../asn1');
23 +
24 +/**
25 + * @see https://tools.ietf.org/html/rfc5280 page 20
26 + * @returns {asn1.univ.Choice}
27 + */
28 +function DirectoryString() {
29 + return new asn1.univ.Choice({
30 + teletexString : new asn1.univ.T61String(),
31 + printableString : new asn1.univ.PrintableString(),
32 + universalString : new asn1.univ.UniversalString(),
33 + utf8String : new asn1.univ.UTF8String(),
34 + bmpString : new asn1.univ.BMPString(),
35 + ia5String : new asn1.univ.IA5String()
36 + });
37 +}
38 +
39 +/**
40 + * https://tools.ietf.org/html/rfc5280 page 20
41 + * @returns {asn1.univ.Choice}
42 + */
43 +function AttributeValue() {
44 + return DirectoryString();
45 +}
46 +
47 +/**
48 + * @see https://tools.ietf.org/html/rfc5280 page 20
49 + * @returns {asn1.univ.ObjectIdentifier}
50 + */
51 +function AttributeType() {
52 + return new asn1.univ.ObjectIdentifier();
53 +}
54 +
55 +/**
56 + * @see https://tools.ietf.org/html/rfc5280 page 20
57 + * @returns {asn1.univ.Sequence}
58 + */
59 +function AttributeTypeAndValue() {
60 + return new asn1.univ.Sequence({
61 + type : AttributeType(),
62 + value : AttributeValue()
63 + });
64 +}
65 +
66 +/**
67 + * https://tools.ietf.org/html/rfc5280 page 116
68 + * @returns {asn1.univ.SetOf}
69 + */
70 +function RelativeDistinguishedName() {
71 + return new asn1.univ.SetOf(AttributeTypeAndValue);
72 +}
73 +
74 +/**
75 + * https://tools.ietf.org/html/rfc5280 page 116
76 + * @returns {asn1.univ.SequenceOf}
77 + */
78 +function RDNSequence() {
79 + return new asn1.univ.SequenceOf(RelativeDistinguishedName);
80 +}
81 +
82 +/**
83 + * @see https://tools.ietf.org/html/rfc5280 page 116
84 + * @returns {asn1.univ.Choice}
85 + */
86 +function Name() {
87 + return new asn1.univ.Choice({
88 + rdnSequence : RDNSequence()
89 + });
90 +}
91 +
92 +/**
93 + * @see https://tools.ietf.org/html/rfc5280 page 18
94 + * @returns {asn1.univ.Sequence}
95 + */
96 +function AlgorithmIdentifier() {
97 + return new asn1.univ.Sequence({
98 + algorithm : new asn1.univ.ObjectIdentifier(),
99 + parameters : new asn1.univ.Null()
100 + });
101 +}
102 +
103 +/**
104 + * @see https://tools.ietf.org/html/rfc5280 page 117
105 + * @returns {asn1.univ.Sequence}
106 + */
107 +function Extension() {
108 + return new asn1.univ.Sequence({
109 + extnID : new asn1.univ.ObjectIdentifier(),
110 + critical : new asn1.univ.Boolean(),
111 + extnValue : new asn1.univ.OctetString()
112 + });
113 +}
114 +
115 +/**
116 + * @see https://tools.ietf.org/html/rfc5280 page 117
117 + * @returns {asn1.univ.SequenceOf}
118 + */
119 +function Extensions() {
120 + return new asn1.univ.SequenceOf(Extension);
121 +}
122 +
123 +/**
124 + * @see https://tools.ietf.org/html/rfc5280 page 117
125 + * @returns {asn1.univ.Choice}
126 + */
127 +function Time() {
128 + return new asn1.univ.Choice({
129 + utcTime : new asn1.univ.UTCTime(),
130 + generalTime : new asn1.univ.GeneralizedTime()
131 + });
132 +}
133 +
134 +/**
135 + * @see https://tools.ietf.org/html/rfc5280 page 117
136 + * @returns {asn1.univ.Sequence}
137 + */
138 +function Validity() {
139 + return new asn1.univ.Sequence({
140 + notBefore : Time(),
141 + notAfter : Time()
142 + });
143 +}
144 +
145 +/**
146 + * @see https://tools.ietf.org/html/rfc5280 page 117
147 + * @returns {asn1.univ.Integer}
148 + */
149 +function CertificateSerialNumber() {
150 + return new asn1.univ.Integer();
151 +}
152 +
153 +/**
154 + * @see https://tools.ietf.org/html/rfc5280 page 117
155 + * @returns {asn1.univ.Sequence}
156 + */
157 +function SubjectPublicKeyInfo() {
158 + return new asn1.univ.Sequence({
159 + algorithm : AlgorithmIdentifier(),
160 + subjectPublicKey : new asn1.univ.BitString()
161 + });
162 +}
163 +
164 +/**
165 + * @see https://tools.ietf.org/html/rfc5280 page 117
166 + * @returns {asn1.univ.BitString}
167 + */
168 +function UniqueIdentifier() {
169 + return new asn1.univ.BitString();
170 +}
171 +
172 +/**
173 + * @see https://tools.ietf.org/html/rfc5280 page 117
174 + * @returns {asn1.univ.Sequence}
175 + */
176 +function TbsCertificate() {
177 + return new asn1.univ.Sequence({
178 + version : CertificateSerialNumber().explicitTag(new asn1.spec.Asn1Tag(asn1.spec.TagClass.Context, asn1.spec.TagFormat.Constructed, 0)),
179 + serialNumber : new asn1.univ.Integer(),
180 + signature : AlgorithmIdentifier(),
181 + issuer : Name(),
182 + validity : Validity(),
183 + subject : Name(),
184 + subjectPublicKeyInfo : SubjectPublicKeyInfo(),
185 + issuerUniqueID : UniqueIdentifier().implicitTag(asn1.spec.TagClass.Context, asn1.spec.TagFormat.Primitive, 1).optional(),
186 + subjectUniqueID : UniqueIdentifier().implicitTag(asn1.spec.TagClass.Context, asn1.spec.TagFormat.Primitive, 2).optional(),
187 + extensions : Extensions().implicitTag(asn1.spec.TagClass.Context, asn1.spec.TagFormat.Primitive, 3).optional()
188 + });
189 +}
190 +
191 +/**
192 + * @see https://tools.ietf.org/html/rfc5280 page 117
193 + * @returns {asn1.univ.Sequence}
194 + */
195 +function X509Certificate() {
196 + return new asn1.univ.Sequence({
197 + tbsCertificate : TbsCertificate(),
198 + signatureAlgorithm : AlgorithmIdentifier(),
199 + signatureValue : new asn1.univ.BitString()
200 + });
201 +}
202 +
203 +function RSAPublicKey() {
204 + return new asn1.univ.Sequence({
205 + modulus : new asn1.univ.Integer(),
206 + publicExponent : new asn1.univ.Integer()
207 + });
208 +}
209 +
210 +/**
211 + * Module Export
212 + */
213 +module.exports = {
214 + X509Certificate : X509Certificate,
215 + RSAPublicKey : RSAPublicKey
216 +};
\ No newline at end of file
webserver.js
+1 -1
@@ -2931,7 +2931,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
2931 if (domain.sessionrecording != null) { features += 0x08000000; } // Server recordings enabled
2932 if (domain.urlswitching === false) { features += 0x10000000; } // Disables the URL switching feature
2933 if (domain.novnc === false) { features += 0x20000000; } // Disables noVNC
2934 - if (domain.mstsc !== true) { features += 0x40000000; } // Disables MSTSC.js
2934 + if (domain.mstsc === false) { features += 0x40000000; } // Disables MSTSC.js
2935 if (obj.isTrustedCert(domain) == false) { features += 0x80000000; } // Indicate we are not using a trusted certificate
2936 if (obj.parent.amtManager != null) { features2 += 0x00000001; } // Indicates that the Intel AMT manager is active
2937 if (obj.parent.firebase != null) { features2 += 0x00000002; } // Indicates the server supports Firebase push messaging