mosquito-transport 1.4.3
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/LICENSE +21 -0
- package/README.md +138 -0
- package/lib/helpers/EnginePath.js +8 -0
- package/lib/helpers/SocketHandler.d.ts +6 -0
- package/lib/helpers/SocketHandler.js +5 -0
- package/lib/helpers/listeners.js +5 -0
- package/lib/helpers/utils.js +105 -0
- package/lib/helpers/values.js +76 -0
- package/lib/helpers/variables.js +13 -0
- package/lib/index.d.ts +442 -0
- package/lib/index.js +1038 -0
- package/lib/products/auth/appleAuth.js +3 -0
- package/lib/products/auth/customAuth.js +267 -0
- package/lib/products/auth/facebookAuth.js +3 -0
- package/lib/products/auth/fallbackAuth.js +3 -0
- package/lib/products/auth/githubAuth.js +3 -0
- package/lib/products/auth/googleAuth.js +106 -0
- package/lib/products/auth/index.js +242 -0
- package/lib/products/auth/tokenizer.js +125 -0
- package/lib/products/auth/twitterAuth.js +3 -0
- package/lib/products/database/base.d.ts +3 -0
- package/lib/products/database/base.js +16 -0
- package/lib/products/database/index.js +644 -0
- package/lib/products/storage/index.js +172 -0
- package/package.json +67 -0
- package/rollup.config.js +34 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023 Anthony
|
|
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.
|
package/README.md
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# mosquito-transport
|
|
2
|
+
|
|
3
|
+
MosquitoTransport is a powerful tool that enables developers to persist and synchronize data between their MongoDB database and frontend applications. It offers a centralized and self-hosted solution for managing server infrastructure and data, along with robust authentication, real-time data updates, scalability, and cross-platform compatibility.
|
|
4
|
+
|
|
5
|
+
Under the hood, mosquito-transport uses Mongodb to store it data and [express](https://www.npmjs.com/package/express), [socket.io](https://www.npmjs.com/package/socket.io) for making request and [jwt](https://www.npmjs.com/package/jsonwebtoken) for signing authentication token, so make sure you have [mongodb](https://www.mongodb.com/docs/manual/installation/) installed before using this package.
|
|
6
|
+
|
|
7
|
+
## Key features of mosquito-transport include:
|
|
8
|
+
|
|
9
|
+
- ### Data Persistence and Synchronization 🔁:
|
|
10
|
+
- Seamlessly persist and synchronize data between MongoDB and frontend applications, ensuring consistency across all clients.
|
|
11
|
+
|
|
12
|
+
- ### Self-Hosted Server 💾:
|
|
13
|
+
- Host your own server infrastructure, giving you full control over data storage, access, and management.
|
|
14
|
+
|
|
15
|
+
- ### User Authentication and Authorization 🔐:
|
|
16
|
+
- 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 🔗:
|
|
19
|
+
- 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 🚨:
|
|
22
|
+
- Enable real-time updates to keep data synchronized across all clients in real-time, providing a seamless user experience.
|
|
23
|
+
|
|
24
|
+
- ### Scalability and Performance 🚛:
|
|
25
|
+
- Benefit from auto-scaling and high performance, allowing your application to handle varying workloads with ease.
|
|
26
|
+
|
|
27
|
+
- ### Cross-Platform Compatibility 📱:
|
|
28
|
+
- Compatible with React Native and web applications, allowing you to build cross-platform solutions with ease.
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
## Installation
|
|
32
|
+
|
|
33
|
+
```sh
|
|
34
|
+
npm install mosquito-transport
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
or using yarn
|
|
38
|
+
|
|
39
|
+
```sh
|
|
40
|
+
yarn add mosquito-transport
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Usage
|
|
44
|
+
|
|
45
|
+
```js
|
|
46
|
+
import MosquitoTransportServer from "mosquito-transport";
|
|
47
|
+
import { MongoClient } from 'mongodb';
|
|
48
|
+
|
|
49
|
+
// create a mongodb instance
|
|
50
|
+
const dbInstance = new MongoClient('mongodb://127.0.0.1:27017', {
|
|
51
|
+
useNewUrlParser: true,
|
|
52
|
+
useUnifiedTopology: true
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
dbInstance.connect().then(() => {
|
|
56
|
+
console.log('connected to mongodb at');
|
|
57
|
+
}).catch(e => {
|
|
58
|
+
console.error('failed to connected to mongodb at');
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
// setup your server
|
|
62
|
+
const serverApp = new MosquitoTransportServer({
|
|
63
|
+
projectName: 'app_name',
|
|
64
|
+
port: 4534, // defaults to 4291
|
|
65
|
+
signerKey: 'random_90_hash_key_for_signing_jwt_tokens', // must be 90 length
|
|
66
|
+
accessKey: 'this_is_my_private_password', // keep this private if you don't provide databaseRules or storageRules
|
|
67
|
+
mongoInstances: {
|
|
68
|
+
// this is where user info and tokens is stored
|
|
69
|
+
admin: {
|
|
70
|
+
instance: dbInstance,
|
|
71
|
+
defaultName: 'ADMIN_DB_NAME'
|
|
72
|
+
},
|
|
73
|
+
// this will be the default db if no dbName was provided
|
|
74
|
+
default: {
|
|
75
|
+
instance: dbInstance,
|
|
76
|
+
defaultName: 'DEFAULT_DB_NAME'
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
databaseRules: ({ auth, collection, value, afterData, beforeData, operation, ...otherProps })=> new Promise((resolve, reject)=> {
|
|
80
|
+
// validate and authorize all incoming request to the database
|
|
81
|
+
if (collection === 'user') {
|
|
82
|
+
if (afterData && auth && auth.uid === value._id) {
|
|
83
|
+
resolve(); // allow read/write
|
|
84
|
+
} else reject('You don`t own this data, stay away'); // reject read/write
|
|
85
|
+
} else if (collection === 'other_paths') {
|
|
86
|
+
// blah, blah, other algorithm ...
|
|
87
|
+
}
|
|
88
|
+
}),
|
|
89
|
+
storageRules: ({...props})=> new Promise(resolve=> {
|
|
90
|
+
// validate and authorize all uploads/downloads
|
|
91
|
+
resolve(true) // handle read/write yourself here
|
|
92
|
+
}),
|
|
93
|
+
googleAuthConfig: {
|
|
94
|
+
clientID: 'your_google_authentication_clientID.apps.googleusercontent.com'
|
|
95
|
+
},
|
|
96
|
+
appleAuthConfig: {
|
|
97
|
+
...props
|
|
98
|
+
},
|
|
99
|
+
...otherProps
|
|
100
|
+
});
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
your server is now ready to be deploy on node.js! 🚀. Now install any mosquito-transport client sdk and start making requests to the server.
|
|
104
|
+
|
|
105
|
+
### SDKs And Hacks
|
|
106
|
+
- [react-native-mosquito-transport](https://github.com/deflexable/react-native-mosquito-transport) for react native apps
|
|
107
|
+
- [mosquito-transport-web](https://github.com/brainbehindx/mosquito-transport-js) for web platform
|
|
108
|
+
- [mongodb-hack-middleware](https://github.com/deflexable/mongodb-middleware-utils) for random query hack and fulltext search hack
|
|
109
|
+
|
|
110
|
+
## Additional Documentations
|
|
111
|
+
- [Logging Level](#logging-levels)
|
|
112
|
+
- [Database Rules](#database-rules)
|
|
113
|
+
- [Storage Rules](#storage-rules)
|
|
114
|
+
- [Authentication](#authentication)
|
|
115
|
+
- [Merge Auth Account](#google-auth-setup)
|
|
116
|
+
- [Google Auth Setup](#google-auth-setup)
|
|
117
|
+
- [Apple Auth Setup](#apple-auth-setup)
|
|
118
|
+
- [Facebook Auth Setup](#facebook-auth-setup)
|
|
119
|
+
- [Twitter Auth Setup](#twitter-auth-setup)
|
|
120
|
+
- [Github Auth Setup](#google-auth-setup)
|
|
121
|
+
- [Fallback Auth Setup](#fallback-auth-setup)
|
|
122
|
+
- [Google Auth Setup](#google-auth-setup)
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
<!-- ## Platform using MosquitoTransport in production
|
|
126
|
+
- [Heavenya - christian events](https://heavenya.com)
|
|
127
|
+
- [Inspire - christian audio](https://inspire.com)
|
|
128
|
+
- [ExamJoint - learn, study and prepare for exam](https://examjoint.com) -->
|
|
129
|
+
|
|
130
|
+
## Contributing
|
|
131
|
+
|
|
132
|
+
See the [contributing guide](CONTRIBUTING.md) to learn how to contribute to the repository and the development workflow.
|
|
133
|
+
|
|
134
|
+
## License
|
|
135
|
+
|
|
136
|
+
MIT
|
|
137
|
+
|
|
138
|
+
---
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import naclPkg from 'tweetnacl';
|
|
2
|
+
import { Scoped } from './variables';
|
|
3
|
+
|
|
4
|
+
const { box, randomBytes } = naclPkg;
|
|
5
|
+
|
|
6
|
+
export const simplifyError = (error, message) => ({
|
|
7
|
+
simpleError: { error, message }
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
export const simplifyCaughtError = (e) => e?.simpleError ? e : simplifyError('unexpected_error', `${e}`);
|
|
11
|
+
|
|
12
|
+
export const getRandomString = (length = 20, number = true, capLetter = true, smallLetter = true) => {
|
|
13
|
+
const randomChars = `${capLetter ? 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' : ''}${smallLetter ? 'abcdefghijklmnopqrstuvwxyz' : ''}${number ? '0123456789' : ''}`;
|
|
14
|
+
|
|
15
|
+
return Array(length).fill(0).map(() => randomChars.charAt(Math.round(Math.random() * randomChars.length))).join('');
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export const IS_RAW_OBJECT = (e) => e && typeof e === 'object' && !Array.isArray(e);
|
|
19
|
+
|
|
20
|
+
export const IS_JSON_OBJECT = (o) => o !== null &&
|
|
21
|
+
typeof o === 'object' &&
|
|
22
|
+
(Object.prototype.toString.call(o) === '[object Object]' ||
|
|
23
|
+
Object.prototype.toString.call(o) === '[object Array]' ||
|
|
24
|
+
Array.isArray(o));
|
|
25
|
+
|
|
26
|
+
export const IS_WHOLE_NUMBER = (v) => typeof v === 'number' && !`${v}`.includes('.');
|
|
27
|
+
|
|
28
|
+
export const queryEntries = (obj, lastPath = '', exceptions = [], seperator = '.') => {
|
|
29
|
+
let o = [];
|
|
30
|
+
|
|
31
|
+
Object.entries(obj).forEach(([key, value]) => {
|
|
32
|
+
if (IS_RAW_OBJECT(value) && !exceptions.includes(key)) {
|
|
33
|
+
o = [...o, ...queryEntries(value, `${lastPath}${key}${seperator}`, exceptions, seperator)];
|
|
34
|
+
} else o.push([`${lastPath}${key}`, value]);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
return o;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export const niceTry = (promise) => new Promise(async resolve => {
|
|
41
|
+
|
|
42
|
+
try {
|
|
43
|
+
const r = await promise();
|
|
44
|
+
resolve(r);
|
|
45
|
+
} catch (e) {
|
|
46
|
+
console.error('niceTry encounter an error: ', e);
|
|
47
|
+
resolve();
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
export const deserializeE2E = (data, projectName) => {
|
|
52
|
+
try {
|
|
53
|
+
const [clientPubKey, clientNonce, clientData] = data.split('.'),
|
|
54
|
+
[_, serverPrivateKey] = Scoped.InstancesData[projectName].E2E_BufferPair || [];
|
|
55
|
+
|
|
56
|
+
if (serverPrivateKey) throw '"e2eKeyPair" is required for decrypting a e2e messages';
|
|
57
|
+
const baseArray = box.open(
|
|
58
|
+
Buffer.from(clientData, 'base64'),
|
|
59
|
+
Buffer.from(clientNonce, 'base64'),
|
|
60
|
+
Buffer.from(clientPubKey, 'base64'),
|
|
61
|
+
serverPrivateKey
|
|
62
|
+
);
|
|
63
|
+
if (!baseArray) throw 'The server was unable to decrypt the reqest body';
|
|
64
|
+
|
|
65
|
+
const decryptedData = JSON.parse(Buffer.from(baseArray).toString('utf8'));
|
|
66
|
+
|
|
67
|
+
return [decryptedData[0], clientPubKey, decryptedData[1]];
|
|
68
|
+
} catch (e) {
|
|
69
|
+
throw simplifyError('decryption_failed', `${e}`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export const serializeE2E = (message, clientPublicKey, projectName) => {
|
|
74
|
+
const nonce = randomBytes(box.nonceLength),
|
|
75
|
+
nonceBase64 = Buffer.from(nonce).toString('base64');
|
|
76
|
+
|
|
77
|
+
const [_, serverPrivateKey] = Scoped.InstancesData[projectName].E2E_BufferPair || [];
|
|
78
|
+
|
|
79
|
+
return `${nonceBase64}.${Buffer.from(
|
|
80
|
+
box(
|
|
81
|
+
Buffer.from(JSON.stringify([
|
|
82
|
+
message
|
|
83
|
+
]), 'utf8'),
|
|
84
|
+
nonce,
|
|
85
|
+
Buffer.from(clientPublicKey, 'base64'),
|
|
86
|
+
serverPrivateKey
|
|
87
|
+
)
|
|
88
|
+
).toString('base64')}`;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export const requestURL = (request) => {
|
|
92
|
+
return new URL(request.url, `http://${request.headers.host}`);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export const getStringExtension = (url) => {
|
|
96
|
+
const r = url.split(/[#?]/)[0].split(".").pop().trim();
|
|
97
|
+
return r === url ? '' : r;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export const interpolate = (x, [y1, x1], [y2, x2]) => {
|
|
101
|
+
return y1 + ((x - x1) * ((y2 - y1) / (x2 - x1)));
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export const encodeBinary = (s) => Buffer.from(s, 'utf8').toString('base64');
|
|
105
|
+
export const decodeBinary = (s) => Buffer.from(s, 'base64').toString('utf8');
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { Scoped } from "./variables";
|
|
2
|
+
import { join } from 'path';
|
|
3
|
+
|
|
4
|
+
export const DEFAULT_DB = Symbol('default_db');
|
|
5
|
+
export const ADMIN_DB_NAME = Symbol('admin_db_name');
|
|
6
|
+
export const ADMIN_DB_URL = Symbol('admin_db');
|
|
7
|
+
|
|
8
|
+
export const DEFAULT_STORAGE_PATH = '';
|
|
9
|
+
export const BACKUP_STORAGE_PATH = '';
|
|
10
|
+
|
|
11
|
+
export const one_day = 86400000,
|
|
12
|
+
one_week = 604800000,
|
|
13
|
+
one_month = 2419200000,
|
|
14
|
+
one_hour = 3600000,
|
|
15
|
+
one_minute = 60000;
|
|
16
|
+
|
|
17
|
+
export const one_mb = 1048576;
|
|
18
|
+
|
|
19
|
+
export const STORAGE_ROUTE = '/storage';
|
|
20
|
+
|
|
21
|
+
export const STORAGE_URL_TO_FILE = (link = '', projectName) => {
|
|
22
|
+
try {
|
|
23
|
+
const url = new URL(link);
|
|
24
|
+
if (!url) throw '';
|
|
25
|
+
return `${STORAGE_PATH(projectName)}${url.pathname.substring(STORAGE_ROUTE.length)}`;
|
|
26
|
+
} catch (e) {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export const STORAGE_PATH = (projectName) => `${STORAGE_PREFIX_PATH(projectName)}/.dump/${projectName}`;
|
|
32
|
+
export const STORAGE_PREFIX_PATH = (projectName) => `${Scoped.InstancesData[projectName].dumpsterPath || process.cwd()}`;
|
|
33
|
+
export const STORAGE_FREEZER_DIR = (projectName) => join(STORAGE_PREFIX_PATH(projectName), '.vid_freezer');
|
|
34
|
+
|
|
35
|
+
export const TOKEN_EXPIRY = (projectName) => (Scoped.InstancesData[projectName].accessTokenInterval || one_hour);
|
|
36
|
+
export const REFRESH_TOKEN_EXPIRY = (projectName) => (Scoped.InstancesData[projectName]?.refreshTokenExpiry || one_month);
|
|
37
|
+
|
|
38
|
+
export const REGEX = {
|
|
39
|
+
LINK_REGEX: () => /(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig,
|
|
40
|
+
EMAIL: () => ({
|
|
41
|
+
test: (t) => typeof t === 'string' &&
|
|
42
|
+
/^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/.test(t) &&
|
|
43
|
+
!!t.trim() &&
|
|
44
|
+
t.trim().length <= 1000
|
|
45
|
+
}),
|
|
46
|
+
USERNAME_REGEX: () => /^[a-zA-Z0-9](_(?!(\.|_))|\.(?!(_|\.))|[a-zA-Z0-9]){2,30}[a-zA-Z0-9]$/,
|
|
47
|
+
PHONE_NUMBER: () => /^[+]?[\s./0-9]*[(]?[0-9]{1,4}[)]?[-\s./0-9]*$/g,
|
|
48
|
+
NAME: () => ({ test: (t) => typeof t === 'string' && !!t.trim() && t.trim().length <= 500 })
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export const EngineRoutes = {
|
|
52
|
+
_listenUserVerification: '_listenUserVerification',
|
|
53
|
+
_customSignin: '_customSignin',
|
|
54
|
+
_customSignup: '_customSignup',
|
|
55
|
+
_refreshAuthToken: '_refreshAuthToken',
|
|
56
|
+
_googleSignin: '_googleSignin',
|
|
57
|
+
_appleSignin: '_appleSignin',
|
|
58
|
+
_facebookSignin: '_facebookSignin',
|
|
59
|
+
_twitterSignin: '_twitterSignin',
|
|
60
|
+
_githubSignin: '_githubSignin',
|
|
61
|
+
_signOut: '_signOut',
|
|
62
|
+
_invalidateToken: '_invalidateToken',
|
|
63
|
+
_uploadFile: '_uploadFile',
|
|
64
|
+
_deleteFile: '_deleteFile',
|
|
65
|
+
_deleteFolder: '_deleteFolder',
|
|
66
|
+
_listenCollection: '_listenCollection',
|
|
67
|
+
_listenDocument: '_listenDocument',
|
|
68
|
+
_startDisconnectWriteTask: '_startDisconnectWriteTask',
|
|
69
|
+
_cancelDisconnectWriteTask: '_cancelDisconnectWriteTask',
|
|
70
|
+
_readDocument: '_readDocument',
|
|
71
|
+
_queryCollection: '_queryCollection',
|
|
72
|
+
_writeDocument: '_writeDocument',
|
|
73
|
+
_writeMapDocument: '_writeMapDocument',
|
|
74
|
+
_documentCount: '_documentCount',
|
|
75
|
+
_areYouOk: '_areYouOk'
|
|
76
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export const Scoped = {
|
|
2
|
+
pendingSignups: {},
|
|
3
|
+
TokenSelfDestruction: {
|
|
4
|
+
RefreshToken: {},
|
|
5
|
+
AccessToken: {}
|
|
6
|
+
},
|
|
7
|
+
cacheTranformVideoTimer: {},
|
|
8
|
+
SequentialUid: {},
|
|
9
|
+
Databases: {},
|
|
10
|
+
serverInstances: {},
|
|
11
|
+
expressInstances: {},
|
|
12
|
+
InstancesData: {}
|
|
13
|
+
}
|