@rustwirebot/rustplus.js 2.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +351 -0
  3. package/camera.js +425 -0
  4. package/cli/index.js +308 -0
  5. package/cli/pair.html +49 -0
  6. package/docs/API.md +101 -0
  7. package/docs/DownloadBundle.md +7 -0
  8. package/docs/PairingFlow.md +19 -0
  9. package/donate.md +10 -0
  10. package/examples/10_shoot_autoturret.js +100 -0
  11. package/examples/1_send_team_chat.js +16 -0
  12. package/examples/2_turn_smart_switch_on.js +21 -0
  13. package/examples/3_turn_smart_switch_off.js +21 -0
  14. package/examples/4_entity_changed_broadcasts.js +58 -0
  15. package/examples/5_download_map_jpeg.js +22 -0
  16. package/examples/6_async_requests.js +35 -0
  17. package/examples/7_render_camera.js +34 -0
  18. package/examples/8_move_ptz_camera.js +56 -0
  19. package/examples/9_zoom_ptz_camera.js +37 -0
  20. package/package.json +48 -0
  21. package/rustplus.js +380 -0
  22. package/rustplus.js.svg +34 -0
  23. package/rustplus.proto +431 -0
  24. package/vendor/push-receiver/LICENSE +21 -0
  25. package/vendor/push-receiver/NOTICE.md +32 -0
  26. package/vendor/push-receiver/android/fcm.js +134 -0
  27. package/vendor/push-receiver/client.js +216 -0
  28. package/vendor/push-receiver/constants.js +53 -0
  29. package/vendor/push-receiver/fcm/index.js +52 -0
  30. package/vendor/push-receiver/fcm/server-key/index.js +67 -0
  31. package/vendor/push-receiver/gcm/android_checkin.proto +96 -0
  32. package/vendor/push-receiver/gcm/checkin.proto +155 -0
  33. package/vendor/push-receiver/gcm/index.js +128 -0
  34. package/vendor/push-receiver/index.js +17 -0
  35. package/vendor/push-receiver/mcs.proto +328 -0
  36. package/vendor/push-receiver/parser.js +276 -0
  37. package/vendor/push-receiver/register/index.js +18 -0
  38. package/vendor/push-receiver/utils/base64/index.js +15 -0
  39. package/vendor/push-receiver/utils/decrypt/index.js +23 -0
  40. package/vendor/push-receiver/utils/http-request/index.js +43 -0
  41. package/vendor/push-receiver/utils/request/index.js +27 -0
  42. package/vendor/push-receiver/utils/timeout/index.js +7 -0
@@ -0,0 +1,34 @@
1
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2
+ <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
3
+ <svg width="100%" height="100%" viewBox="0 0 119 26" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
4
+ <g transform="matrix(2.46772,0,0,2.46772,-90.2851,-41.164)">
5
+ <g transform="matrix(12,0,0,12,36.5865,27.181)">
6
+ <path d="M0.438,-0.438L0.438,-0.688L0.188,-0.688L0.188,-0.438L0.438,-0.438ZM0,-0L0,-0.875L0.625,-0.875L0.625,-0.25L0.438,-0.25L0.438,-0.188L0.625,-0.188L0.625,-0L0.25,-0L0.25,-0.25L0.188,-0.25L0.188,-0L0,-0Z" style="fill:rgb(211,19,0);fill-rule:nonzero;"/>
7
+ </g>
8
+ <g transform="matrix(12,0,0,12,44.8131,27.181)">
9
+ <path d="M0,-0L0,-0.875L0.188,-0.875L0.188,-0.188L0.438,-0.188L0.438,-0.875L0.625,-0.875L0.625,-0L0,-0Z" style="fill:rgb(211,19,0);fill-rule:nonzero;"/>
10
+ </g>
11
+ <g transform="matrix(12,0,0,12,53.0396,27.181)">
12
+ <path d="M0,-0L0,-0.188L0.438,-0.188L0.438,-0.375L0,-0.375L0,-0.875L0.625,-0.875L0.625,-0.688L0.188,-0.688L0.188,-0.563L0.625,-0.563L0.625,-0L0,-0Z" style="fill:rgb(211,19,0);fill-rule:nonzero;"/>
13
+ </g>
14
+ <g transform="matrix(12,0,0,12,61.2662,27.181)">
15
+ <path d="M0.188,-0L0.188,-0.688L0,-0.688L0,-0.875L0.563,-0.875L0.563,-0.688L0.375,-0.688L0.375,-0L0.188,-0Z" style="fill:rgb(211,19,0);fill-rule:nonzero;"/>
16
+ </g>
17
+ </g>
18
+ <g transform="matrix(1,0,0,1,-25.4858,7.58166)">
19
+ <g transform="matrix(29.6126,0,0,29.6126,101.035,13.9337)">
20
+ <path d="M0.361,-0L0.361,-0.253L0.108,-0.253L0.108,-0.325L0.361,-0.325L0.361,-0.578L0.434,-0.578L0.434,-0.325L0.687,-0.325L0.687,-0.253L0.434,-0.253L0.434,-0L0.361,-0Z" style="fill:rgb(211,19,0);fill-rule:nonzero;"/>
21
+ </g>
22
+ </g>
23
+ <g transform="matrix(1,0,0,1,-30.1812,9.51199)">
24
+ <g transform="matrix(14.8063,0,0,14.8063,126.06,16.399)">
25
+ <rect x="0" y="-0.188" width="0.188" height="0.188" style="fill-rule:nonzero;"/>
26
+ </g>
27
+ <g transform="matrix(14.8063,0,0,14.8063,129.733,16.399)">
28
+ <path d="M0,-0L0,-0.188L0.25,-0.188L0.375,-0.313L0.375,-0.688L0,-0.688L0,-0.875L0.563,-0.875L0.563,-0.188L0.375,-0L0,-0Z" style="fill-rule:nonzero;"/>
29
+ </g>
30
+ <g transform="matrix(14.8063,0,0,14.8063,138.958,16.399)">
31
+ <path d="M0,-0L0,-0.188L0.438,-0.188L0.438,-0.375L0,-0.375L0,-0.875L0.625,-0.875L0.625,-0.688L0.188,-0.688L0.188,-0.563L0.625,-0.563L0.625,-0L0,-0Z" style="fill-rule:nonzero;"/>
32
+ </g>
33
+ </g>
34
+ </svg>
package/rustplus.proto ADDED
@@ -0,0 +1,431 @@
1
+ syntax = "proto2";
2
+ package rustplus;
3
+
4
+ message Vector2 {
5
+ optional float x = 1;
6
+ optional float y = 2;
7
+ }
8
+
9
+ message Vector3 {
10
+ optional float x = 1;
11
+ optional float y = 2;
12
+ optional float z = 3;
13
+ }
14
+
15
+ message Vector4 {
16
+ optional float x = 1;
17
+ optional float y = 2;
18
+ optional float z = 3;
19
+ optional float w = 4;
20
+ }
21
+
22
+ message Half3 {
23
+ optional float x = 1;
24
+ optional float y = 2;
25
+ optional float z = 3;
26
+ }
27
+
28
+ message Color {
29
+ optional float r = 1;
30
+ optional float g = 2;
31
+ optional float b = 3;
32
+ optional float a = 4;
33
+ }
34
+
35
+ message Ray {
36
+ optional Vector3 origin = 1;
37
+ optional Vector3 direction = 2;
38
+ }
39
+
40
+ message ClanActionResult {
41
+ required int32 requestId = 1;
42
+ required int32 result = 2;
43
+ required bool hasClanInfo = 3;
44
+ optional ClanInfo clanInfo = 4;
45
+ }
46
+
47
+ message ClanInfo {
48
+ required int64 clanId = 1;
49
+ required string name = 2;
50
+ required int64 created = 3;
51
+ required uint64 creator = 4;
52
+ optional string motd = 5;
53
+ optional int64 motdTimestamp = 6;
54
+ optional uint64 motdAuthor = 7;
55
+ optional bytes logo = 8;
56
+ optional sint32 color = 9;
57
+ repeated ClanInfo.Role roles = 10;
58
+ repeated ClanInfo.Member members = 11;
59
+ repeated ClanInfo.Invite invites = 12;
60
+ optional int32 maxMemberCount = 13;
61
+
62
+ message Role {
63
+ required int32 roleId = 1;
64
+ required int32 rank = 2;
65
+ required string name = 3;
66
+ required bool canSetMotd = 4;
67
+ required bool canSetLogo = 5;
68
+ required bool canInvite = 6;
69
+ required bool canKick = 7;
70
+ required bool canPromote = 8;
71
+ required bool canDemote = 9;
72
+ required bool canSetPlayerNotes = 10;
73
+ required bool canAccessLogs = 11;
74
+ }
75
+
76
+ message Member {
77
+ required uint64 steamId = 1;
78
+ required int32 roleId = 2;
79
+ required int64 joined = 3;
80
+ required int64 lastSeen = 4;
81
+ optional string notes = 5;
82
+ optional bool online = 6;
83
+ }
84
+
85
+ message Invite {
86
+ required uint64 steamId = 1;
87
+ required uint64 recruiter = 2;
88
+ required int64 timestamp = 3;
89
+ }
90
+ }
91
+
92
+ message ClanLog {
93
+ required int64 clanId = 1;
94
+ repeated ClanLog.Entry logEntries = 2;
95
+
96
+ message Entry {
97
+ required int64 timestamp = 1;
98
+ required string eventKey = 2;
99
+ optional string arg1 = 3;
100
+ optional string arg2 = 4;
101
+ optional string arg3 = 5;
102
+ optional string arg4 = 6;
103
+ }
104
+ }
105
+
106
+ message ClanInvitations {
107
+ repeated ClanInvitations.Invitation invitations = 1;
108
+
109
+ message Invitation {
110
+ required int64 clanId = 1;
111
+ required uint64 recruiter = 2;
112
+ required int64 timestamp = 3;
113
+ }
114
+ }
115
+
116
+ enum AppEntityType {
117
+ Switch = 1;
118
+ Alarm = 2;
119
+ StorageMonitor = 3;
120
+ }
121
+
122
+ enum AppMarkerType {
123
+ Undefined = 0;
124
+ Player = 1;
125
+ Explosion = 2;
126
+ VendingMachine = 3;
127
+ CH47 = 4;
128
+ CargoShip = 5;
129
+ Crate = 6;
130
+ GenericRadius = 7;
131
+ PatrolHelicopter = 8;
132
+ }
133
+
134
+ message AppRequest {
135
+ required uint32 seq = 1;
136
+ required uint64 playerId = 2;
137
+ required int32 playerToken = 3;
138
+ optional uint32 entityId = 4;
139
+ optional AppEmpty getInfo = 8;
140
+ optional AppEmpty getTime = 9;
141
+ optional AppEmpty getMap = 10;
142
+ optional AppEmpty getTeamInfo = 11;
143
+ optional AppEmpty getTeamChat = 12;
144
+ optional AppSendMessage sendTeamMessage = 13;
145
+ optional AppEmpty getEntityInfo = 14;
146
+ optional AppSetEntityValue setEntityValue = 15;
147
+ optional AppEmpty checkSubscription = 16;
148
+ optional AppFlag setSubscription = 17;
149
+ optional AppEmpty getMapMarkers = 18;
150
+ optional AppPromoteToLeader promoteToLeader = 20;
151
+ optional AppEmpty getClanInfo = 21;
152
+ optional AppSendMessage setClanMotd = 22;
153
+ optional AppEmpty getClanChat = 23;
154
+ optional AppSendMessage sendClanMessage = 24;
155
+ optional AppGetNexusAuth getNexusAuth = 25;
156
+ optional AppCameraSubscribe cameraSubscribe = 30;
157
+ optional AppEmpty cameraUnsubscribe = 31;
158
+ optional AppCameraInput cameraInput = 32;
159
+ }
160
+
161
+ message AppMessage {
162
+ optional AppResponse response = 1;
163
+ optional AppBroadcast broadcast = 2;
164
+ }
165
+
166
+ message AppResponse {
167
+ required uint32 seq = 1;
168
+ optional AppSuccess success = 4;
169
+ optional AppError error = 5;
170
+ optional AppInfo info = 6;
171
+ optional AppTime time = 7;
172
+ optional AppMap map = 8;
173
+ optional AppTeamInfo teamInfo = 9;
174
+ optional AppTeamChat teamChat = 10;
175
+ optional AppEntityInfo entityInfo = 11;
176
+ optional AppFlag flag = 12;
177
+ optional AppMapMarkers mapMarkers = 13;
178
+ optional AppClanInfo clanInfo = 15;
179
+ optional AppClanChat clanChat = 16;
180
+ optional AppNexusAuth nexusAuth = 17;
181
+ optional AppCameraInfo cameraSubscribeInfo = 20;
182
+ }
183
+
184
+ message AppBroadcast {
185
+ optional AppTeamChanged teamChanged = 4;
186
+ optional AppNewTeamMessage teamMessage = 5;
187
+ optional AppEntityChanged entityChanged = 6;
188
+ optional AppClanChanged clanChanged = 7;
189
+ optional AppNewClanMessage clanMessage = 8;
190
+ optional AppCameraRays cameraRays = 10;
191
+ }
192
+
193
+ message AppEmpty {
194
+ }
195
+
196
+ message AppSendMessage {
197
+ required string message = 1;
198
+ }
199
+
200
+ message AppSetEntityValue {
201
+ required bool value = 1;
202
+ }
203
+
204
+ message AppPromoteToLeader {
205
+ required uint64 steamId = 1;
206
+ }
207
+
208
+ message AppGetNexusAuth {
209
+ required string appKey = 1;
210
+ }
211
+
212
+ message AppSuccess {
213
+ }
214
+
215
+ message AppError {
216
+ required string error = 1;
217
+ }
218
+
219
+ message AppFlag {
220
+ required bool value = 1;
221
+ }
222
+
223
+ message AppInfo {
224
+ required string name = 1;
225
+ required string headerImage = 2;
226
+ required string url = 3;
227
+ required string map = 4;
228
+ required uint32 mapSize = 5;
229
+ required uint32 wipeTime = 6;
230
+ required uint32 players = 7;
231
+ required uint32 maxPlayers = 8;
232
+ required uint32 queuedPlayers = 9;
233
+ optional uint32 seed = 10;
234
+ optional uint32 salt = 11;
235
+ optional string logoImage = 12;
236
+ optional string nexus = 13;
237
+ optional int32 nexusId = 14;
238
+ optional string nexusZone = 15;
239
+ }
240
+
241
+ message AppTime {
242
+ required float dayLengthMinutes = 1;
243
+ required float timeScale = 2;
244
+ required float sunrise = 3;
245
+ required float sunset = 4;
246
+ required float time = 5;
247
+ }
248
+
249
+ message AppMap {
250
+ required uint32 width = 1;
251
+ required uint32 height = 2;
252
+ required bytes jpgImage = 3;
253
+ required int32 oceanMargin = 4;
254
+ repeated AppMap.Monument monuments = 5;
255
+ optional string background = 6;
256
+
257
+ message Monument {
258
+ required string token = 1;
259
+ required float x = 2;
260
+ required float y = 3;
261
+ }
262
+ }
263
+
264
+ message AppEntityInfo {
265
+ required AppEntityType type = 1;
266
+ required AppEntityPayload payload = 3;
267
+ }
268
+
269
+ message AppEntityPayload {
270
+ optional bool value = 1;
271
+ repeated AppEntityPayload.Item items = 2;
272
+ optional int32 capacity = 3;
273
+ optional bool hasProtection = 4;
274
+ optional uint32 protectionExpiry = 5;
275
+
276
+ message Item {
277
+ required int32 itemId = 1;
278
+ required int32 quantity = 2;
279
+ required bool itemIsBlueprint = 3;
280
+ }
281
+ }
282
+
283
+ message AppTeamInfo {
284
+ required uint64 leaderSteamId = 1;
285
+ repeated AppTeamInfo.Member members = 2;
286
+ repeated AppTeamInfo.Note mapNotes = 3;
287
+ repeated AppTeamInfo.Note leaderMapNotes = 4;
288
+
289
+ message Member {
290
+ required uint64 steamId = 1;
291
+ required string name = 2;
292
+ required float x = 3;
293
+ required float y = 4;
294
+ required bool isOnline = 5;
295
+ required uint32 spawnTime = 6;
296
+ required bool isAlive = 7;
297
+ required uint32 deathTime = 8;
298
+ }
299
+
300
+ message Note {
301
+ required int32 type = 2;
302
+ required float x = 3;
303
+ required float y = 4;
304
+ }
305
+ }
306
+
307
+ message AppTeamMessage {
308
+ required uint64 steamId = 1;
309
+ required string name = 2;
310
+ required string message = 3;
311
+ required string color = 4;
312
+ required uint32 time = 5;
313
+ }
314
+
315
+ message AppTeamChat {
316
+ repeated AppTeamMessage messages = 1;
317
+ }
318
+
319
+ message AppMarker {
320
+ required uint32 id = 1;
321
+ required AppMarkerType type = 2;
322
+ required float x = 3;
323
+ required float y = 4;
324
+ optional uint64 steamId = 5;
325
+ optional float rotation = 6;
326
+ optional float radius = 7;
327
+ optional Vector4 color1 = 8;
328
+ optional Vector4 color2 = 9;
329
+ optional float alpha = 10;
330
+ optional string name = 11;
331
+ optional bool outOfStock = 12;
332
+ repeated AppMarker.SellOrder sellOrders = 13;
333
+
334
+ message SellOrder {
335
+ required int32 itemId = 1;
336
+ required int32 quantity = 2;
337
+ required int32 currencyId = 3;
338
+ required int32 costPerItem = 4;
339
+ required int32 amountInStock = 5;
340
+ required bool itemIsBlueprint = 6;
341
+ required bool currencyIsBlueprint = 7;
342
+ optional float itemCondition = 8;
343
+ optional float itemConditionMax = 9;
344
+ }
345
+ }
346
+
347
+ message AppMapMarkers {
348
+ repeated AppMarker markers = 1;
349
+ }
350
+
351
+ message AppClanInfo {
352
+ optional ClanInfo clanInfo = 1;
353
+ }
354
+
355
+ message AppClanMessage {
356
+ required uint64 steamId = 1;
357
+ required string name = 2;
358
+ required string message = 3;
359
+ required int64 time = 4;
360
+ }
361
+
362
+ message AppClanChat {
363
+ repeated AppClanMessage messages = 1;
364
+ }
365
+
366
+ message AppNexusAuth {
367
+ required string serverId = 1;
368
+ required int32 playerToken = 2;
369
+ }
370
+
371
+ message AppTeamChanged {
372
+ required uint64 playerId = 1;
373
+ required AppTeamInfo teamInfo = 2;
374
+ }
375
+
376
+ message AppNewTeamMessage {
377
+ required AppTeamMessage message = 1;
378
+ }
379
+
380
+ message AppEntityChanged {
381
+ required uint32 entityId = 1;
382
+ required AppEntityPayload payload = 2;
383
+ }
384
+
385
+ message AppClanChanged {
386
+ optional ClanInfo clanInfo = 1;
387
+ }
388
+
389
+ message AppNewClanMessage {
390
+ required int64 clanId = 1;
391
+ required AppClanMessage message = 2;
392
+ }
393
+
394
+ message AppCameraSubscribe {
395
+ required string cameraId = 1;
396
+ }
397
+
398
+ message AppCameraInput {
399
+ required int32 buttons = 1;
400
+ required Vector2 mouseDelta = 2;
401
+ }
402
+
403
+ message AppCameraInfo {
404
+ required int32 width = 1;
405
+ required int32 height = 2;
406
+ required float nearPlane = 3;
407
+ required float farPlane = 4;
408
+ required int32 controlFlags = 5;
409
+ }
410
+
411
+ message AppCameraRays {
412
+ required float verticalFov = 1;
413
+ required int32 sampleOffset = 2;
414
+ required bytes rayData = 3;
415
+ required float distance = 4;
416
+ repeated AppCameraRays.Entity entities = 5;
417
+
418
+ enum EntityType {
419
+ Tree = 1;
420
+ Player = 2;
421
+ }
422
+
423
+ message Entity {
424
+ required uint32 entityId = 1;
425
+ required EntityType type = 2;
426
+ required Vector3 position = 3;
427
+ required Vector3 rotation = 4;
428
+ required Vector3 size = 5;
429
+ optional string name = 6;
430
+ }
431
+ }
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2017 Matthieu Lemoine
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,32 @@
1
+ # NOTICE — vendored dependency
2
+
3
+ The code in this folder (`vendor/push-receiver`) is vendored directly into
4
+ `@rustwirebot/rustplus.js` so that this package keeps working even if the
5
+ upstream `@liamcottle/push-receiver` npm package is ever unpublished or
6
+ its source repository becomes unavailable.
7
+
8
+ Attribution chain (all under the MIT License, see ./LICENSE):
9
+
10
+ 1. Original project: **push-receiver** by Matthieu Lemoine (2017)
11
+ https://github.com/MatthieuLemoine/push-receiver
12
+ 2. Fork with Android FCM registration support: **@liamcottle/push-receiver**
13
+ by Liam Cottle
14
+ https://github.com/liamcottle/push-receiver
15
+ 3. Vendored copy maintained here as part of **@rustwirebot/rustplus.js**
16
+ by BotForge Studios, with the following compatibility/security fixes:
17
+ - `register/index.js` was updated from the removed `require('uuid/v4')`
18
+ subpath (uuid v3-style) to the current `uuid` named export
19
+ (`const { v4: uuidv4 } = require('uuid')`).
20
+ - The original `request` / `request-promise` HTTP clients (both
21
+ deprecated upstream and flagged with known critical vulnerabilities)
22
+ were replaced with a small `axios`-based wrapper,
23
+ [`utils/http-request`](./utils/http-request/index.js), that
24
+ reproduces the exact same call signature and return-value behaviour
25
+ (form-encoding, raw-Buffer responses via `encoding: null`, and
26
+ throwing on non-2xx responses) so no other code had to change.
27
+ This was verified against a local test HTTP server covering
28
+ form-encoding, binary responses, retry-on-failure, and error
29
+ handling — all matching the original behaviour.
30
+
31
+ No other functional changes were made. All credit for the original
32
+ implementation belongs to Matthieu Lemoine and Liam Cottle.
@@ -0,0 +1,134 @@
1
+ const crypto = require("crypto");
2
+ const { checkIn } = require("../gcm");
3
+ const { waitFor } = require("../utils/timeout");
4
+ const request = require("../utils/request");
5
+
6
+ class AndroidFCM {
7
+
8
+ static async register(apiKey, projectId, gcmSenderId, gmsAppId, androidPackageName, androidPackageCert) {
9
+
10
+ // create firebase installation
11
+ const installationAuthToken = await this.installRequest(apiKey, projectId, gmsAppId, androidPackageName, androidPackageCert);
12
+
13
+ // checkin gcm
14
+ const checkInResponse = await checkIn();
15
+
16
+ // register gcm
17
+ const fcmToken = await this.registerRequest(checkInResponse.androidId, checkInResponse.securityToken, installationAuthToken, apiKey, gcmSenderId, gmsAppId, androidPackageName, androidPackageCert);
18
+
19
+ return {
20
+ gcm: {
21
+ androidId: checkInResponse.androidId,
22
+ securityToken: checkInResponse.securityToken,
23
+ },
24
+ fcm: {
25
+ token: fcmToken,
26
+ },
27
+ };
28
+
29
+ }
30
+
31
+ static async installRequest(apiKey, projectId, gmsAppId, androidPackage, androidCert) {
32
+
33
+ // send firebase installation request
34
+ const response = await request({
35
+ url: `https://firebaseinstallations.googleapis.com/v1/projects/${projectId}/installations`,
36
+ method: 'POST',
37
+ headers: {
38
+ "Accept": "application/json",
39
+ "Content-Type": "application/json",
40
+ "X-Android-Package": androidPackage,
41
+ "X-Android-Cert": androidCert,
42
+ "x-firebase-client": "android-min-sdk/23 fire-core/20.0.0 device-name/a21snnxx device-brand/samsung device-model/a21s android-installer/com.android.vending fire-android/30 fire-installations/17.0.0 fire-fcm/22.0.0 android-platform/ kotlin/1.9.23 android-target-sdk/34",
43
+ "x-firebase-client-log-type": "3",
44
+ "x-goog-api-key": apiKey,
45
+ "User-Agent": "Dalvik/2.1.0 (Linux; U; Android 11; SM-A217F Build/RP1A.200720.012)",
46
+ },
47
+ body: JSON.stringify({
48
+ "fid": this.generateFirebaseFID(),
49
+ "appId": gmsAppId,
50
+ "authVersion": "FIS_v2",
51
+ "sdkVersion": "a:17.0.0",
52
+ }),
53
+ });
54
+
55
+ // ensure auth token received
56
+ const data = JSON.parse(response);
57
+ if(!data || !data.authToken || !data.authToken.token){
58
+ throw new Error(`Failed to get Firebase installation AuthToken: ${data}`);
59
+ }
60
+
61
+ return data.authToken.token;
62
+
63
+ }
64
+
65
+ static async registerRequest(androidId, securityToken, installationAuthToken, apiKey, gcmSenderId, gmsAppId, androidPackageName, androidPackageCert, retry = 0) {
66
+
67
+ // register gcm
68
+ const response = await request({
69
+ url: "https://android.clients.google.com/c2dm/register3",
70
+ method: 'POST',
71
+ headers: {
72
+ "Authorization": `AidLogin ${androidId}:${securityToken}`,
73
+ "Content-Type": "application/x-www-form-urlencoded",
74
+ },
75
+ form: {
76
+ "device": androidId,
77
+ "app": androidPackageName,
78
+ "cert": androidPackageCert,
79
+ "app_ver": "1",
80
+ "X-subtype" : gcmSenderId,
81
+ "X-app_ver" : "1",
82
+ "X-osv" : "29",
83
+ "X-cliv" : "fiid-21.1.1",
84
+ "X-gmsv" : "220217001",
85
+ // "X-appid" : "",
86
+ "X-scope" : "*",
87
+ "X-Goog-Firebase-Installations-Auth" : installationAuthToken,
88
+ "X-gms_app_id" : gmsAppId,
89
+ "X-Firebase-Client" : "android-min-sdk/23 fire-core/20.0.0 device-name/a21snnxx device-brand/samsung device-model/a21s android-installer/com.android.vending fire-android/30 fire-installations/17.0.0 fire-fcm/22.0.0 android-platform/ kotlin/1.9.23 android-target-sdk/34",
90
+ // "X-firebase-app-name-hash" : "",
91
+ "X-Firebase-Client-Log-Type": "1",
92
+ "X-app_ver_name": "1",
93
+ "target_ver": "31",
94
+ "sender": gcmSenderId,
95
+ },
96
+ });
97
+
98
+ // retry a few times if needed
99
+ if(response.includes('Error')){
100
+ console.warn(`Register request has failed with ${response}`);
101
+ if(retry >= 5){
102
+ throw new Error('GCM register has failed');
103
+ }
104
+ console.warn(`Retry... ${retry + 1}`);
105
+ await waitFor(1000);
106
+ return this.registerRequest(androidId, securityToken, installationAuthToken, apiKey, gcmSenderId, gmsAppId, androidPackageName, androidPackageCert, retry + 1);
107
+ }
108
+
109
+ // extract fcm token from response
110
+ return response.split("=")[1];
111
+
112
+ }
113
+
114
+ /**
115
+ * Generates a Firebase ID
116
+ * https://github.com/firebase/firebase-js-sdk/blob/3670ab83c563dc96f2ad0120c551f46fe7d1bb7b/packages/installations/src/helpers/generate-fid.ts#L27
117
+ * https://github.com/rixcian/firebase-electron/blob/master/src/core/fcm/index.ts#L124
118
+ * @returns {string}
119
+ */
120
+ static generateFirebaseFID() {
121
+
122
+ const buf = crypto.randomBytes(17);
123
+
124
+ // replace the first 4 bits with the constant FID header of 0b0111
125
+ buf[0] = 0b01110000 | (buf[0] & 0b00001111);
126
+
127
+ // encode to base64 and remove padding
128
+ return buf.toString("base64").replace(/=/g, "");
129
+
130
+ }
131
+
132
+ }
133
+
134
+ module.exports = AndroidFCM;