mosquito-transport 1.4.3 → 1.4.5

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.
package/README.md CHANGED
@@ -6,25 +6,19 @@ Under the hood, mosquito-transport uses Mongodb to store it data and [express](h
6
6
 
7
7
  ## Key features of mosquito-transport include:
8
8
 
9
- - ### Data Persistence and Synchronization 🔁:
9
+ - Data Persistence and Synchronization 🔁:
10
10
  - Seamlessly persist and synchronize data between MongoDB and frontend applications, ensuring consistency across all clients.
11
-
12
- - ### Self-Hosted Server 💾:
11
+ - Self-Hosted Server 💾:
13
12
  - Host your own server infrastructure, giving you full control over data storage, access, and management.
14
-
15
- - ### User Authentication and Authorization 🔐:
13
+ - User Authentication and Authorization 🔐:
16
14
  - Easily implement user authentication and authorization using JWT (JSON Web Tokens), providing secure access control to your application's resources.
17
-
18
- - ### End-to-End Encryption 🔗:
15
+ - End-to-End Encryption 🔗:
19
16
  - Optionally enforce end-to-end encryption by allowing only encrypted data to be transmitted between client and server, ensuring data privacy and security.
20
-
21
- - ### Real-Time Data Updates 🚨:
17
+ - Real-Time Data Updates 🚨:
22
18
  - Enable real-time updates to keep data synchronized across all clients in real-time, providing a seamless user experience.
23
-
24
- - ### Scalability and Performance 🚛:
19
+ - Scalability and Performance 🚛:
25
20
  - Benefit from auto-scaling and high performance, allowing your application to handle varying workloads with ease.
26
-
27
- - ### Cross-Platform Compatibility 📱:
21
+ - Cross-Platform Compatibility 📱:
28
22
  - Compatible with React Native and web applications, allowing you to build cross-platform solutions with ease.
29
23
 
30
24
 
package/TODO ADDED
@@ -0,0 +1,3 @@
1
+ - add method for creating user account
2
+ - add method for login user account
3
+ - server favicon for api
@@ -2,4 +2,5 @@ import SubscriptionListener from "subscription-listener";
2
2
 
3
3
  export const StorageListener = new SubscriptionListener();
4
4
  export const DisconnectionWriteTaskListener = new SubscriptionListener();
5
- export const UserCountReadyListener = new SubscriptionListener();;
5
+ export const UserCountReadyListener = new SubscriptionListener();
6
+ export const SignoutUserSignal = new SubscriptionListener();
@@ -53,7 +53,7 @@ export const deserializeE2E = (data, projectName) => {
53
53
  const [clientPubKey, clientNonce, clientData] = data.split('.'),
54
54
  [_, serverPrivateKey] = Scoped.InstancesData[projectName].E2E_BufferPair || [];
55
55
 
56
- if (serverPrivateKey) throw '"e2eKeyPair" is required for decrypting a e2e messages';
56
+ if (!serverPrivateKey) throw '"e2eKeyPair" is required for decrypting a e2e messages';
57
57
  const baseArray = box.open(
58
58
  Buffer.from(clientData, 'base64'),
59
59
  Buffer.from(clientNonce, 'base64'),
package/lib/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Auth, Db, Document, MongoClient, SortDirection, UpdateDescription } from "mongodb";
1
+ import { Db, Document, MongoClient, SortDirection, UpdateDescription } from "mongodb";
2
2
  import express from "express";
3
3
  import { CorsOptions } from "cors";
4
4
  import { Sort } from "mongodb";
@@ -223,6 +223,8 @@ interface MSocketHandshake {
223
223
  };
224
224
  /**
225
225
  * the access token of the user that initiated this handshake
226
+ *
227
+ * N/B: make sure to always revalidate this when making sensitive request
226
228
  */
227
229
  userToken: string | undefined;
228
230
  }
@@ -279,7 +281,7 @@ interface MosquitoServerConfig {
279
281
  mongoInstances: MongoInstancesMap;
280
282
  mergeAuthAccount?: boolean;
281
283
  transformMediaRoute?: '*' | TransformMediaRoute[];
282
- transformMediaCleanupTimeout?: string;
284
+ transformMediaCleanupTimeout?: number;
283
285
  sneakSignupAuth?: (config: SneakSignupAuthConfig) => SneakSignupAuthResult;
284
286
  googleAuthConfig?: GoogleAuthConfig;
285
287
  appleAuthConfig?: AppleAuthConfig;
@@ -297,6 +299,10 @@ interface MosquitoServerConfig {
297
299
  accessTokenInterval?: number;
298
300
  refreshTokenExpiry?: number;
299
301
  dumpsterPath?: string;
302
+ /**
303
+ * require an e2e public and private key like:
304
+ * `['public key', 'private key']`
305
+ */
300
306
  e2eKeyPair?: string[] | undefined;
301
307
  enforceE2E?: boolean;
302
308
  preMiddlewares?: Function[] | Function;
@@ -397,8 +403,25 @@ interface RawBodyRequest extends express.Request {
397
403
  export default class MosquitoDbServer {
398
404
  constructor(config: MosquitoServerConfig);
399
405
 
406
+ /**
407
+ * the directory where storage files are saved
408
+ */
409
+ get storagePath(): string;
410
+
411
+ /**
412
+ * quickly generate an end-to-end encryption key for your server
413
+ * @returns [public_string, private_string]
414
+ */
415
+ get sampleE2E(): string[];
416
+
400
417
  getDatabase(dbName?: string, dbUrl?: string): Db;
401
418
 
419
+ /**
420
+ * purge all tokens references for a user and sign-out the user immediately
421
+ * @param uid uid of the user you are signing out
422
+ */
423
+ signOutUser(uid: string): Promise<void>;
424
+
402
425
  /**
403
426
  * verify token to check if it was trully created using signerKey without checking against the expiry or local token reference
404
427
  *
package/lib/index.js CHANGED
@@ -14,11 +14,11 @@ import { validateFacebookAuthConfig } from "./products/auth/facebookAuth.js";
14
14
  import { validateGithubAuthConfig } from "./products/auth/githubAuth.js";
15
15
  import { validateTwitterAuthConfig } from "./products/auth/twitterAuth.js";
16
16
  import { validateFallbackAuthConfig } from "./products/auth/fallbackAuth.js";
17
- import { DisconnectionWriteTaskListener, StorageListener, UserCountReadyListener } from "./helpers/listeners.js";
17
+ import { DisconnectionWriteTaskListener, SignoutUserSignal, StorageListener, UserCountReadyListener } from "./helpers/listeners.js";
18
18
  import EnginePath from "./helpers/EnginePath.js";
19
19
  import { Server } from "socket.io";
20
20
  import http from 'http';
21
- import { mkdir, readFile, unlink, writeFile, rm as rmdir } from "fs/promises";
21
+ import { mkdir, readFile, unlink, writeFile, rm } from "fs/promises";
22
22
  import { cleanUserToken } from "./products/auth/customAuth.js";
23
23
  import { invalidateToken } from "./products/auth/customAuth.js";
24
24
  import cors from 'cors';
@@ -26,6 +26,9 @@ import { parse, stringify } from 'json-buffer';
26
26
  import { exec } from "child_process";
27
27
  import { createRequire } from 'node:module';
28
28
  import { MongoClient } from "mongodb";
29
+ import naclPkg from 'tweetnacl';
30
+
31
+ const { sign: e2eSign } = naclPkg;
29
32
 
30
33
  const _require = createRequire(import.meta.url);
31
34
 
@@ -356,7 +359,18 @@ const useMosquitoServer = (app, config) => {
356
359
  authLiveRoutes({ ...config }).map(e => e(socket, scope));
357
360
  databaseLiveRoutes({ ...config }).map(e => e(socket, scope));
358
361
 
359
- if (initAuthHandshake?._m_internal || !onSocketSnapshot) return;
362
+ if (initAuthHandshake?._m_internal || !onSocketSnapshot) {
363
+ if (initAuthHandshake?._from_base) {
364
+ const signoutSignal = SignoutUserSignal.listenTo('d', () => {
365
+ socket.emit('_signal_signout');
366
+ });
367
+
368
+ socket.on('disconnect', () => {
369
+ signoutSignal();
370
+ });
371
+ }
372
+ return;
373
+ }
360
374
  try {
361
375
  const { e2e, ugly, accessKey: ak } = initAuthHandshake;
362
376
 
@@ -555,7 +569,7 @@ export default class MosquitoTransportServer {
555
569
 
556
570
  (async () => {
557
571
  try {
558
- await rmdir(`${STORAGE_PREFIX_PATH(this.projectName)}/.vid_freezer`, {
572
+ await rm(`${STORAGE_PREFIX_PATH(this.projectName)}/.vid_freezer`, {
559
573
  recursive: true,
560
574
  force: true
561
575
  });
@@ -567,6 +581,24 @@ export default class MosquitoTransportServer {
567
581
  get storagePath() {
568
582
  return STORAGE_PATH(this.projectName);
569
583
  }
584
+
585
+ get sampleE2E() {
586
+ const keyPair = e2eSign.keyPair();
587
+ return [
588
+ keyPair.publicKey,
589
+ keyPair.secretKey
590
+ ].map(v => Buffer.from(v).toString('base64'));
591
+ }
592
+
593
+ signOutUser = async (uid) => {
594
+ const db = getDB(this.projectName, ADMIN_DB_NAME, ADMIN_DB_URL);
595
+ await Promise.all([
596
+ db.collection(EnginePath.refreshTokenStore).deleteMany({ uid }),
597
+ db.collection(EnginePath.tokenStore).deleteMany({ uid })
598
+ ]);
599
+ SignoutUserSignal.dispatch('d', uid);
600
+ }
601
+
570
602
  verifyToken = (token, isRefreshToken) => verifyJWT(token, this.projectName, isRefreshToken);
571
603
  validateToken = (token, isRefreshToken) => validateJWT(token, this.projectName, isRefreshToken);
572
604
  invalidateToken = (token, isRefreshToken) => invalidateToken(token, this.projectName, isRefreshToken);
@@ -720,7 +752,7 @@ export default class MosquitoTransportServer {
720
752
  path = `${STORAGE_PATH(this.projectName)}/${path}`;
721
753
 
722
754
  removeVideoFreezer(path, true);
723
- await rmdir(path, {
755
+ await rm(path, {
724
756
  recursive: true,
725
757
  force: true
726
758
  });
@@ -325,6 +325,8 @@ const validateDbBody = (body, route) => {
325
325
  if (!b.scope) throw simplifyError('required_field', `scope is required field at index ${i}`);
326
326
  });
327
327
  } else throw simplifyError('invalid_field_type', `"value" must be an array`);
328
+ } else if (k === 'stepping') {
329
+ if (typeof v !== 'boolean') throw simplifyError('invalid_value', `Invalid value supplied to stepping, expected a boolean but got ${v}`);
328
330
  } else throw simplifyError('invalid_field', `Unknown field "${k}"`);
329
331
  });
330
332
  } else if (route === '_readDocument' || route === '_listenDocument') {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mosquito-transport",
3
- "version": "1.4.3",
3
+ "version": "1.4.5",
4
4
  "description": "MosquitoTransport is a powerful tool that helps persist and synchronize data between your MongoDB database and frontend applications",
5
5
  "main": "lib/index.js",
6
6
  "type": "module",
@@ -46,7 +46,6 @@
46
46
  "jsonwebtoken": "^9.0.0",
47
47
  "lodash": "^4.17.21",
48
48
  "mkdirp": "^3.0.1",
49
- "mongodb": "^5.3.0",
50
49
  "node-fetch": "^3.3.1",
51
50
  "set-large-timeout": "^1.0.1",
52
51
  "socket.io": "^4.6.1",
@@ -54,6 +53,7 @@
54
53
  "tweetnacl": "^1.0.3"
55
54
  },
56
55
  "devDependencies": {
56
+ "@types/mongodb": "^4.0.7",
57
57
  "@babel/cli": "^7.21.5",
58
58
  "@babel/core": "^7.21.5",
59
59
  "@babel/node": "^7.20.7",