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