omnibiofex 2.8.1 → 2.8.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/package.json +1 -1
- package/src/auth.js +16 -22
- package/src/commands/account.js +18 -27
- package/src/commands/earnings.js +21 -27
- package/src/commands/publish.js +21 -31
- package/src/firebase.js +104 -0
package/package.json
CHANGED
package/src/auth.js
CHANGED
|
@@ -3,22 +3,19 @@ const { URL } = require('url');
|
|
|
3
3
|
const axios = require('axios');
|
|
4
4
|
const chalk = require('chalk');
|
|
5
5
|
const inquirer = require('inquirer');
|
|
6
|
-
const
|
|
7
|
-
const {
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
const app = initializeApp(firebaseConfig);
|
|
21
|
-
const auth = getAuth(app);
|
|
6
|
+
const Conf = require('conf');
|
|
7
|
+
const { sendSignInLinkToEmail } = require('firebase/auth');
|
|
8
|
+
const { app, auth, db } = require('./firebase');
|
|
9
|
+
|
|
10
|
+
// Use the shared auth instance
|
|
11
|
+
const config = new Conf({
|
|
12
|
+
projectName: 'omnibiofex',
|
|
13
|
+
schema: {
|
|
14
|
+
token: { type: 'string' },
|
|
15
|
+
refreshToken: { type: 'string' },
|
|
16
|
+
expiresAt: { type: 'number' }
|
|
17
|
+
}
|
|
18
|
+
});
|
|
22
19
|
|
|
23
20
|
const LOCAL_PORT = 8765;
|
|
24
21
|
const CALLBACK_PATH = '/auth/callback';
|
|
@@ -157,12 +154,10 @@ function startLocalServer() {
|
|
|
157
154
|
console.log('Local server received request:', req.url);
|
|
158
155
|
|
|
159
156
|
if (url.pathname === CALLBACK_PATH) {
|
|
160
|
-
// 🔥 FIX: Properly decode URL parameters
|
|
161
157
|
let token = url.searchParams.get('token');
|
|
162
158
|
let refreshToken = url.searchParams.get('refreshToken');
|
|
163
159
|
const error = url.searchParams.get('error');
|
|
164
160
|
|
|
165
|
-
// 🔥 FIX: Replace spaces with + (URL decoding issue)
|
|
166
161
|
if (token && token.includes(' ')) {
|
|
167
162
|
console.log(chalk.yellow('⚠️ Token contains spaces, fixing...'));
|
|
168
163
|
token = token.replace(/ /g, '+');
|
|
@@ -177,7 +172,6 @@ function startLocalServer() {
|
|
|
177
172
|
console.log('Token length:', token.length);
|
|
178
173
|
console.log('Token starts with:', token.substring(0, 20));
|
|
179
174
|
|
|
180
|
-
// 🔥 Validate token format
|
|
181
175
|
if (!token.startsWith('eyJ')) {
|
|
182
176
|
console.error('✗ Invalid token format');
|
|
183
177
|
res.writeHead(400, { 'Content-Type': 'text/html' });
|
|
@@ -279,8 +273,10 @@ async function refreshAuthToken() {
|
|
|
279
273
|
try {
|
|
280
274
|
console.log(chalk.gray('🔄 Refreshing authentication token...'));
|
|
281
275
|
|
|
276
|
+
const apiKey = app.options.apiKey; // Get API key from the shared Firebase app
|
|
277
|
+
|
|
282
278
|
const response = await axios.post(
|
|
283
|
-
`https://securetoken.googleapis.com/v1/token?key=${
|
|
279
|
+
`https://securetoken.googleapis.com/v1/token?key=${apiKey}`,
|
|
284
280
|
new URLSearchParams({
|
|
285
281
|
grant_type: 'refresh_token',
|
|
286
282
|
refresh_token: refreshToken
|
|
@@ -294,7 +290,6 @@ async function refreshAuthToken() {
|
|
|
294
290
|
|
|
295
291
|
const { id_token, refresh_token, expires_in } = response.data;
|
|
296
292
|
|
|
297
|
-
// 🔥 Validate new token
|
|
298
293
|
if (!id_token || !id_token.startsWith('eyJ')) {
|
|
299
294
|
throw new Error('Invalid token received from refresh endpoint');
|
|
300
295
|
}
|
|
@@ -347,7 +342,6 @@ async function getAuthToken() {
|
|
|
347
342
|
process.exit(1);
|
|
348
343
|
}
|
|
349
344
|
|
|
350
|
-
// 🔥 Validate token before returning
|
|
351
345
|
if (!token.startsWith('eyJ')) {
|
|
352
346
|
console.error(chalk.red('Stored token is corrupted. Please login again.'));
|
|
353
347
|
config.delete('authToken');
|
package/src/commands/account.js
CHANGED
|
@@ -1,22 +1,9 @@
|
|
|
1
1
|
const chalk = require('chalk');
|
|
2
2
|
const open = require('open');
|
|
3
3
|
const { getAuthToken, isAuthenticated } = require('../auth');
|
|
4
|
+
const { db, getCurrentUserUid, getCurrentUserEmail } = require('../firebase');
|
|
4
5
|
const { PremiumSpinner, sleep } = require('../utils/display');
|
|
5
|
-
const {
|
|
6
|
-
const { getAuth } = require('firebase/auth');
|
|
7
|
-
const { getFirestore, collection, query, where, getDocs } = require('firebase/firestore');
|
|
8
|
-
|
|
9
|
-
const firebaseConfig = {
|
|
10
|
-
apiKey: "AIzaSyDlgXId4pLlYqm-MDuhfz3dLH24KBRHkw8",
|
|
11
|
-
authDomain: "omnibiofex-x.firebaseapp.com",
|
|
12
|
-
projectId: "omnibiofex-x",
|
|
13
|
-
storageBucket: "omnibiofex-x.firebasestorage.app",
|
|
14
|
-
messagingSenderId: "292246591666",
|
|
15
|
-
appId: "1:292246591666:web:a182851585e4b0f79511ab"
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
const app = initializeApp(firebaseConfig);
|
|
19
|
-
const db = getFirestore(app);
|
|
6
|
+
const { collection, query, where, getDocs } = require('firebase/firestore');
|
|
20
7
|
|
|
21
8
|
async function credits() {
|
|
22
9
|
if (!isAuthenticated()) {
|
|
@@ -74,23 +61,24 @@ async function usage() {
|
|
|
74
61
|
return;
|
|
75
62
|
}
|
|
76
63
|
|
|
64
|
+
// Get user UID from stored token
|
|
65
|
+
const uid = getCurrentUserUid();
|
|
66
|
+
const email = getCurrentUserEmail();
|
|
67
|
+
|
|
68
|
+
if (!uid) {
|
|
69
|
+
console.error(chalk.red('✗ Could not extract user ID from token.'));
|
|
70
|
+
console.error(chalk.gray('Please run: obx login'));
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
|
|
77
74
|
const spinner = new PremiumSpinner('Fetching usage statistics');
|
|
78
75
|
spinner.start();
|
|
79
76
|
|
|
80
77
|
try {
|
|
81
|
-
const auth = getAuth(app);
|
|
82
|
-
const user = auth.currentUser;
|
|
83
|
-
|
|
84
|
-
if (!user) {
|
|
85
|
-
spinner.fail('Not authenticated');
|
|
86
|
-
console.error(chalk.red('Please run: obx login'));
|
|
87
|
-
return;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
78
|
// Fetch ALL missions (real data)
|
|
91
79
|
const allMissionsQuery = query(
|
|
92
80
|
collection(db, 'missions'),
|
|
93
|
-
where('uid', '==',
|
|
81
|
+
where('uid', '==', uid)
|
|
94
82
|
);
|
|
95
83
|
|
|
96
84
|
const allMissionsSnapshot = await getDocs(allMissionsQuery);
|
|
@@ -113,7 +101,7 @@ async function usage() {
|
|
|
113
101
|
// Fetch published missions for earnings
|
|
114
102
|
const publishedQuery = query(
|
|
115
103
|
collection(db, 'missions'),
|
|
116
|
-
where('uid', '==',
|
|
104
|
+
where('uid', '==', uid),
|
|
117
105
|
where('isPublished', '==', true)
|
|
118
106
|
);
|
|
119
107
|
|
|
@@ -136,7 +124,10 @@ async function usage() {
|
|
|
136
124
|
console.log(chalk.white.bold('📊 USAGE STATISTICS'));
|
|
137
125
|
console.log(chalk.hex('#F24E1E')('═══════════════════════════════════════════════════════════\n'));
|
|
138
126
|
|
|
139
|
-
console.log(chalk.
|
|
127
|
+
console.log(chalk.gray(` 👤 User: ${chalk.white(email || 'Unknown')}`));
|
|
128
|
+
console.log(chalk.gray(` 🆔 UID: ${chalk.gray(uid.substring(0, 16))}...`));
|
|
129
|
+
|
|
130
|
+
console.log(chalk.white(`\n 🎯 Total Missions: ${chalk.green(totalMissions)}`));
|
|
140
131
|
console.log(chalk.white(` ✅ Completed: ${chalk.green(completedMissions)}`));
|
|
141
132
|
console.log(chalk.white(` ⏳ Active: ${chalk.yellow(activeMissions)}`));
|
|
142
133
|
console.log(chalk.white(` ⛽ RCC Spent: ${chalk.green(totalRCCSpent.toLocaleString())}`));
|
package/src/commands/earnings.js
CHANGED
|
@@ -1,21 +1,8 @@
|
|
|
1
1
|
const chalk = require('chalk');
|
|
2
|
-
const {
|
|
2
|
+
const { isAuthenticated } = require('../auth');
|
|
3
|
+
const { db, getCurrentUserUid, getCurrentUserEmail, isTokenValid } = require('../firebase');
|
|
3
4
|
const { PremiumSpinner, sleep } = require('../utils/display');
|
|
4
|
-
const {
|
|
5
|
-
const { getAuth } = require('firebase/auth');
|
|
6
|
-
const { getFirestore, collection, query, where, orderBy, limit, getDocs } = require('firebase/firestore');
|
|
7
|
-
|
|
8
|
-
const firebaseConfig = {
|
|
9
|
-
apiKey: "AIzaSyDlgXId4pLlYqm-MDuhfz3dLH24KBRHkw8",
|
|
10
|
-
authDomain: "omnibiofex-x.firebaseapp.com",
|
|
11
|
-
projectId: "omnibiofex-x",
|
|
12
|
-
storageBucket: "omnibiofex-x.firebasestorage.app",
|
|
13
|
-
messagingSenderId: "292246591666",
|
|
14
|
-
appId: "1:292246591666:web:a182851585e4b0f79511ab"
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
const app = initializeApp(firebaseConfig);
|
|
18
|
-
const db = getFirestore(app);
|
|
5
|
+
const { collection, query, where, orderBy, limit, getDocs } = require('firebase/firestore');
|
|
19
6
|
|
|
20
7
|
async function earnings() {
|
|
21
8
|
if (!isAuthenticated()) {
|
|
@@ -23,23 +10,24 @@ async function earnings() {
|
|
|
23
10
|
return;
|
|
24
11
|
}
|
|
25
12
|
|
|
13
|
+
// Get user UID from stored token (NOT from auth.currentUser)
|
|
14
|
+
const uid = getCurrentUserUid();
|
|
15
|
+
const email = getCurrentUserEmail();
|
|
16
|
+
|
|
17
|
+
if (!uid) {
|
|
18
|
+
console.error(chalk.red('✗ Could not extract user ID from token.'));
|
|
19
|
+
console.error(chalk.gray('Please run: obx login'));
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
|
|
26
23
|
const spinner = new PremiumSpinner('Fetching your earnings data');
|
|
27
24
|
spinner.start();
|
|
28
25
|
|
|
29
26
|
try {
|
|
30
|
-
const auth = getAuth(app);
|
|
31
|
-
const user = auth.currentUser;
|
|
32
|
-
|
|
33
|
-
if (!user) {
|
|
34
|
-
spinner.fail('Not authenticated');
|
|
35
|
-
console.error(chalk.red('Please run: obx login'));
|
|
36
|
-
return;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
27
|
// Fetch real published missions with earnings data
|
|
40
28
|
const publishedQuery = query(
|
|
41
29
|
collection(db, 'missions'),
|
|
42
|
-
where('uid', '==',
|
|
30
|
+
where('uid', '==', uid),
|
|
43
31
|
where('isPublished', '==', true),
|
|
44
32
|
orderBy('publishedAt', 'desc'),
|
|
45
33
|
limit(100)
|
|
@@ -87,8 +75,11 @@ async function earnings() {
|
|
|
87
75
|
console.log(chalk.hex('#F24E1E')('\n═══════════════════════════════════════════════════════════'));
|
|
88
76
|
console.log(chalk.white.bold('💰 EARNINGS DASHBOARD'));
|
|
89
77
|
console.log(chalk.hex('#F24E1E')('═══════════════════════════════════════════════════════════\n'));
|
|
78
|
+
|
|
79
|
+
console.log(chalk.gray(` 👤 User: ${chalk.white(email || 'Unknown')}`));
|
|
80
|
+
console.log(chalk.gray(` 🆔 UID: ${chalk.gray(uid.substring(0, 16))}...`));
|
|
90
81
|
|
|
91
|
-
console.log(chalk.white.bold('📊 OVERVIEW'));
|
|
82
|
+
console.log(chalk.white.bold('\n\n📊 OVERVIEW'));
|
|
92
83
|
console.log(chalk.gray('─'.repeat(60)));
|
|
93
84
|
console.log(chalk.white(`\n 💰 Total Earnings: ${chalk.green('₹' + totalEarnings.toLocaleString())}`));
|
|
94
85
|
console.log(chalk.white(` 📅 This Month: ${chalk.green('₹' + thisMonthEarnings.toLocaleString())}`));
|
|
@@ -126,6 +117,9 @@ async function earnings() {
|
|
|
126
117
|
console.log(chalk.white(` 💰 Earnings: ${chalk.green('₹' + (m.earnings || 0).toLocaleString())}`));
|
|
127
118
|
console.log(chalk.gray(` 📅 Published: ${publishedDate}`));
|
|
128
119
|
});
|
|
120
|
+
} else {
|
|
121
|
+
console.log(chalk.yellow('\n\n ⚠️ No published research yet.'));
|
|
122
|
+
console.log(chalk.gray(' Run "obx publish" to publish your first research and start earning.\n'));
|
|
129
123
|
}
|
|
130
124
|
|
|
131
125
|
console.log(chalk.hex('#F24E1E')('\n═══════════════════════════════════════════════════════════\n'));
|
package/src/commands/publish.js
CHANGED
|
@@ -1,22 +1,9 @@
|
|
|
1
1
|
const chalk = require('chalk');
|
|
2
2
|
const inquirer = require('inquirer');
|
|
3
3
|
const { getAuthToken, isAuthenticated } = require('../auth');
|
|
4
|
+
const { db, getCurrentUserUid, getCurrentUserEmail } = require('../firebase');
|
|
4
5
|
const { PremiumSpinner, sleep } = require('../utils/display');
|
|
5
|
-
const {
|
|
6
|
-
const { getAuth } = require('firebase/auth');
|
|
7
|
-
const { getFirestore, collection, query, where, orderBy, limit, getDocs, doc, updateDoc } = require('firebase/firestore');
|
|
8
|
-
|
|
9
|
-
const firebaseConfig = {
|
|
10
|
-
apiKey: "AIzaSyDlgXId4pLlYqm-MDuhfz3dLH24KBRHkw8",
|
|
11
|
-
authDomain: "omnibiofex-x.firebaseapp.com",
|
|
12
|
-
projectId: "omnibiofex-x",
|
|
13
|
-
storageBucket: "omnibiofex-x.firebasestorage.app",
|
|
14
|
-
messagingSenderId: "292246591666",
|
|
15
|
-
appId: "1:292246591666:web:a182851585e4b0f79511ab"
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
const app = initializeApp(firebaseConfig);
|
|
19
|
-
const db = getFirestore(app);
|
|
6
|
+
const { collection, query, where, orderBy, limit, getDocs, doc, updateDoc } = require('firebase/firestore');
|
|
20
7
|
|
|
21
8
|
async function publish(missionId) {
|
|
22
9
|
if (!isAuthenticated()) {
|
|
@@ -24,34 +11,35 @@ async function publish(missionId) {
|
|
|
24
11
|
return;
|
|
25
12
|
}
|
|
26
13
|
|
|
14
|
+
// Get user UID from stored token
|
|
15
|
+
const uid = getCurrentUserUid();
|
|
16
|
+
const email = getCurrentUserEmail();
|
|
17
|
+
|
|
18
|
+
if (!uid) {
|
|
19
|
+
console.error(chalk.red('✗ Could not extract user ID from token.'));
|
|
20
|
+
console.error(chalk.gray('Please run: obx login'));
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
|
|
27
24
|
console.log(chalk.hex('#F24E1E')('\n═══════════════════════════════════════════════════════════'));
|
|
28
25
|
console.log(chalk.white.bold('📤 PUBLISH RESEARCH'));
|
|
29
26
|
console.log(chalk.hex('#F24E1E')('═══════════════════════════════════════════════════════════\n'));
|
|
30
|
-
|
|
31
|
-
|
|
27
|
+
|
|
28
|
+
console.log(chalk.gray(` 👤 User: ${chalk.white(email || 'Unknown')}`));
|
|
29
|
+
console.log(chalk.gray(` 🆔 UID: ${chalk.gray(uid.substring(0, 16))}...`));
|
|
32
30
|
|
|
33
31
|
// If no mission ID provided, fetch real missions from Firestore
|
|
34
32
|
if (!missionId) {
|
|
35
|
-
console.log(chalk.gray('
|
|
33
|
+
console.log(chalk.gray('\nFetching your completed missions...\n'));
|
|
36
34
|
|
|
37
35
|
const spinner = new PremiumSpinner('Loading missions from database');
|
|
38
36
|
spinner.start();
|
|
39
37
|
|
|
40
38
|
try {
|
|
41
|
-
// Get authenticated user
|
|
42
|
-
const auth = getAuth(app);
|
|
43
|
-
const user = auth.currentUser;
|
|
44
|
-
|
|
45
|
-
if (!user) {
|
|
46
|
-
spinner.fail('Not authenticated');
|
|
47
|
-
console.error(chalk.red('Please run: obx login'));
|
|
48
|
-
return;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
39
|
// Fetch real completed missions from Firestore
|
|
52
40
|
const missionsQuery = query(
|
|
53
41
|
collection(db, 'missions'),
|
|
54
|
-
where('uid', '==',
|
|
42
|
+
where('uid', '==', uid),
|
|
55
43
|
where('status', '==', 'completed'),
|
|
56
44
|
where('isPublished', '==', false),
|
|
57
45
|
orderBy('createdAt', 'desc'),
|
|
@@ -117,6 +105,8 @@ async function publish(missionId) {
|
|
|
117
105
|
try {
|
|
118
106
|
spinner.update('Fetching mission data');
|
|
119
107
|
const missionRef = doc(db, 'missions', missionId);
|
|
108
|
+
|
|
109
|
+
// Get the mission document
|
|
120
110
|
const missionSnap = await getDocs(query(collection(db, 'missions'), where('__name__', '==', missionId)));
|
|
121
111
|
|
|
122
112
|
if (missionSnap.empty) {
|
|
@@ -155,8 +145,8 @@ async function publish(missionId) {
|
|
|
155
145
|
downloads: 0,
|
|
156
146
|
citations: 0,
|
|
157
147
|
earnings: 0,
|
|
158
|
-
authorName:
|
|
159
|
-
authorEmail:
|
|
148
|
+
authorName: email || 'Anonymous Researcher',
|
|
149
|
+
authorEmail: email || 'unknown@example.com'
|
|
160
150
|
});
|
|
161
151
|
|
|
162
152
|
spinner.succeed('Research published successfully!');
|
package/src/firebase.js
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
const { initializeApp, getApps } = require('firebase/app');
|
|
2
|
+
const { getAuth } = require('firebase/auth');
|
|
3
|
+
const { getFirestore } = require('firebase/firestore');
|
|
4
|
+
const Conf = require('conf');
|
|
5
|
+
|
|
6
|
+
const firebaseConfig = {
|
|
7
|
+
apiKey: "AIzaSyDlgXId4pLlYqm-MDuhfz3dLH24KBRHkw8",
|
|
8
|
+
authDomain: "omnibiofex-x.firebaseapp.com",
|
|
9
|
+
projectId: "omnibiofex-x",
|
|
10
|
+
storageBucket: "omnibiofex-x.firebasestorage.app",
|
|
11
|
+
messagingSenderId: "292246591666",
|
|
12
|
+
appId: "1:292246591666:web:a182851585e4b0f79511ab"
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
// Initialize Firebase only once
|
|
16
|
+
let app;
|
|
17
|
+
if (getApps().length === 0) {
|
|
18
|
+
app = initializeApp(firebaseConfig);
|
|
19
|
+
} else {
|
|
20
|
+
app = getApps()[0];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const auth = getAuth(app);
|
|
24
|
+
const db = getFirestore(app);
|
|
25
|
+
|
|
26
|
+
// Shared Conf storage for tokens
|
|
27
|
+
const tokenStore = new Conf({
|
|
28
|
+
projectName: 'omnibiofex',
|
|
29
|
+
schema: {
|
|
30
|
+
token: { type: 'string' },
|
|
31
|
+
refreshToken: { type: 'string' },
|
|
32
|
+
expiresAt: { type: 'number' }
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Decode JWT token to extract user info
|
|
38
|
+
* @returns {Object|null} - { uid, email } or null if no token
|
|
39
|
+
*/
|
|
40
|
+
function decodeToken() {
|
|
41
|
+
const token = tokenStore.get('token');
|
|
42
|
+
if (!token) return null;
|
|
43
|
+
|
|
44
|
+
try {
|
|
45
|
+
// JWT format: header.payload.signature
|
|
46
|
+
const parts = token.split('.');
|
|
47
|
+
if (parts.length !== 3) return null;
|
|
48
|
+
|
|
49
|
+
// Decode payload (base64url)
|
|
50
|
+
const payload = parts[1];
|
|
51
|
+
const decoded = Buffer.from(payload, 'base64').toString('utf8');
|
|
52
|
+
const data = JSON.parse(decoded);
|
|
53
|
+
|
|
54
|
+
return {
|
|
55
|
+
uid: data.user_id || data.sub,
|
|
56
|
+
email: data.email,
|
|
57
|
+
exp: data.exp
|
|
58
|
+
};
|
|
59
|
+
} catch (error) {
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Get current user UID from stored token
|
|
66
|
+
* @returns {string|null} - User UID or null
|
|
67
|
+
*/
|
|
68
|
+
function getCurrentUserUid() {
|
|
69
|
+
const decoded = decodeToken();
|
|
70
|
+
return decoded ? decoded.uid : null;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Get current user email from stored token
|
|
75
|
+
* @returns {string|null} - User email or null
|
|
76
|
+
*/
|
|
77
|
+
function getCurrentUserEmail() {
|
|
78
|
+
const decoded = decodeToken();
|
|
79
|
+
return decoded ? decoded.email : null;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Check if token is valid (not expired)
|
|
84
|
+
* @returns {boolean}
|
|
85
|
+
*/
|
|
86
|
+
function isTokenValid() {
|
|
87
|
+
const decoded = decodeToken();
|
|
88
|
+
if (!decoded || !decoded.exp) return false;
|
|
89
|
+
|
|
90
|
+
// JWT exp is in seconds, Date.now() is in milliseconds
|
|
91
|
+
const now = Math.floor(Date.now() / 1000);
|
|
92
|
+
return decoded.exp > now;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
module.exports = {
|
|
96
|
+
app,
|
|
97
|
+
auth,
|
|
98
|
+
db,
|
|
99
|
+
tokenStore,
|
|
100
|
+
decodeToken,
|
|
101
|
+
getCurrentUserUid,
|
|
102
|
+
getCurrentUserEmail,
|
|
103
|
+
isTokenValid
|
|
104
|
+
};
|