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 +7 -13
- package/TODO +3 -0
- package/lib/helpers/listeners.js +2 -1
- package/lib/helpers/utils.js +1 -1
- package/lib/index.d.ts +25 -2
- package/lib/index.js +37 -5
- package/lib/products/database/index.js +2 -0
- package/package.json +2 -2
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
|
-
-
|
|
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
package/lib/helpers/listeners.js
CHANGED
|
@@ -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();
|
package/lib/helpers/utils.js
CHANGED
|
@@ -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 {
|
|
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?:
|
|
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
|
|
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)
|
|
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
|
|
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
|
|
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
|
+
"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",
|