@ciscode/authentication-kit 1.0.43 → 1.1.1
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 +57 -73
- package/package.json +68 -43
- package/.github/workflows/ci .yml +0 -36
- package/.github/workflows/publish.yml +0 -37
- package/CODE_OF_CONDUCT +0 -38
- package/CONTRIBUTING.md +0 -40
- package/SECURITY +0 -31
- package/azure-pipelines.yml +0 -100
- package/src/config/db.config.js +0 -21
- package/src/config/passport.config.js +0 -280
- package/src/controllers/auth.controller.js +0 -566
- package/src/controllers/passwordReset.controller.js +0 -127
- package/src/controllers/permission.controller.js +0 -81
- package/src/controllers/roles.controller.js +0 -108
- package/src/controllers/user.controller.js +0 -283
- package/src/index.js +0 -32
- package/src/middleware/auth.middleware.js +0 -16
- package/src/middleware/authenticate.js +0 -25
- package/src/middleware/rbac.middleware.js +0 -24
- package/src/middleware/tenant.middleware.js +0 -16
- package/src/models/client.model.js +0 -39
- package/src/models/permission.model.js +0 -9
- package/src/models/role.model.js +0 -14
- package/src/models/tenant.model.js +0 -9
- package/src/models/user.model.js +0 -51
- package/src/routes/admin.routes.js +0 -8
- package/src/routes/auth.routes.js +0 -77
- package/src/routes/passwordReset.routes.js +0 -8
- package/src/routes/permission.routes.js +0 -17
- package/src/routes/roles.routes.js +0 -11
- package/src/routes/user.routes.js +0 -22
- package/src/utils/helper.js +0 -26
|
@@ -1,280 +0,0 @@
|
|
|
1
|
-
const passport = require('passport');
|
|
2
|
-
const LocalStrategy = require('passport-local').Strategy;
|
|
3
|
-
const AzureStrategy = require('passport-azure-ad-oauth2').Strategy;
|
|
4
|
-
const GoogleStrategy = require('passport-google-oauth20').Strategy;
|
|
5
|
-
const FacebookStrategy = require('passport-facebook').Strategy;
|
|
6
|
-
const bcrypt = require('bcryptjs');
|
|
7
|
-
const jwtDecode = require('jsonwebtoken').decode;
|
|
8
|
-
const User = require('../models/user.model');
|
|
9
|
-
const Client = require('../models/client.model');
|
|
10
|
-
require('dotenv').config();
|
|
11
|
-
|
|
12
|
-
/* ── Lockout settings for local login ───────────────────── */
|
|
13
|
-
const MAX_FAILED = parseInt(process.env.MAX_FAILED_LOGIN_ATTEMPTS, 10) || 3;
|
|
14
|
-
const LOCK_TIME_MIN = parseInt(process.env.ACCOUNT_LOCK_TIME_MINUTES, 10) || 15;
|
|
15
|
-
const LOCK_TIME_MS = LOCK_TIME_MIN * 60 * 1000;
|
|
16
|
-
|
|
17
|
-
/* ── Default tenant for staff created via Google/Facebook ─ */
|
|
18
|
-
const DEFAULT_TENANT_ID = process.env.DEFAULT_TENANT_ID || 'social-staff';
|
|
19
|
-
|
|
20
|
-
/* ── Local (email/password) for staff ───────────────────── */
|
|
21
|
-
passport.use(
|
|
22
|
-
new LocalStrategy(
|
|
23
|
-
{ usernameField: 'email', passwordField: 'password', passReqToCallback: true },
|
|
24
|
-
async (req, email, password, done) => {
|
|
25
|
-
try {
|
|
26
|
-
const query = { email };
|
|
27
|
-
if (req.body.tenantId) query.tenantId = String(req.body.tenantId).trim();
|
|
28
|
-
|
|
29
|
-
const user = await User.findOne(query);
|
|
30
|
-
if (!user) return done(null, false, { message: 'Incorrect email (or tenant).' });
|
|
31
|
-
|
|
32
|
-
if (user.lockUntil && user.lockUntil > Date.now()) {
|
|
33
|
-
return done(null, false, { message: `Account locked until ${new Date(user.lockUntil).toLocaleString()}.` });
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
const ok = await bcrypt.compare(password, user.password);
|
|
37
|
-
if (!ok) {
|
|
38
|
-
user.failedLoginAttempts += 1;
|
|
39
|
-
if (user.failedLoginAttempts >= MAX_FAILED) user.lockUntil = Date.now() + LOCK_TIME_MS;
|
|
40
|
-
await user.save();
|
|
41
|
-
return done(null, false, { message: 'Incorrect password.' });
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
user.failedLoginAttempts = 0;
|
|
45
|
-
user.lockUntil = undefined;
|
|
46
|
-
await user.save();
|
|
47
|
-
|
|
48
|
-
return done(null, user);
|
|
49
|
-
} catch (err) { return done(err); }
|
|
50
|
-
}
|
|
51
|
-
)
|
|
52
|
-
);
|
|
53
|
-
|
|
54
|
-
/* ── Microsoft (Users) ──────────────────────────────────── */
|
|
55
|
-
passport.use(
|
|
56
|
-
new AzureStrategy(
|
|
57
|
-
{
|
|
58
|
-
clientID: process.env.MICROSOFT_CLIENT_ID,
|
|
59
|
-
clientSecret: process.env.MICROSOFT_CLIENT_SECRET,
|
|
60
|
-
callbackURL: process.env.MICROSOFT_CALLBACK_URL, // e.g. /api/auth/microsoft/callback
|
|
61
|
-
},
|
|
62
|
-
async (_at, _rt, params, _profile, done) => {
|
|
63
|
-
try {
|
|
64
|
-
const decoded = jwtDecode(params.id_token);
|
|
65
|
-
const microsoftId = decoded.oid;
|
|
66
|
-
const email = decoded.preferred_username;
|
|
67
|
-
const name = decoded.name;
|
|
68
|
-
const tenantId = decoded.tid;
|
|
69
|
-
|
|
70
|
-
let user = await User.findOne({ $or: [{ microsoftId }, { email }] });
|
|
71
|
-
if (!user) {
|
|
72
|
-
user = new User({ email, name, tenantId, microsoftId, roles: [], status: 'active' });
|
|
73
|
-
await user.save();
|
|
74
|
-
} else {
|
|
75
|
-
let changed = false;
|
|
76
|
-
if (!user.microsoftId) { user.microsoftId = microsoftId; changed = true; }
|
|
77
|
-
if (!user.tenantId) { user.tenantId = tenantId; changed = true; }
|
|
78
|
-
if (changed) await user.save();
|
|
79
|
-
}
|
|
80
|
-
return done(null, user);
|
|
81
|
-
} catch (err) { return done(err); }
|
|
82
|
-
}
|
|
83
|
-
)
|
|
84
|
-
);
|
|
85
|
-
|
|
86
|
-
/* ── Microsoft (Clients) ────────────────────────────────── */
|
|
87
|
-
passport.use(
|
|
88
|
-
'azure_ad_oauth2_client',
|
|
89
|
-
new AzureStrategy(
|
|
90
|
-
{
|
|
91
|
-
clientID: process.env.MICROSOFT_CLIENT_ID_CLIENT || process.env.MICROSOFT_CLIENT_ID,
|
|
92
|
-
clientSecret: process.env.MICROSOFT_CLIENT_SECRET_CLIENT || process.env.MICROSOFT_CLIENT_SECRET,
|
|
93
|
-
callbackURL: process.env.MICROSOFT_CALLBACK_URL_CLIENT, // e.g. /api/auth/client/microsoft/callback
|
|
94
|
-
},
|
|
95
|
-
async (_at, _rt, params, _profile, done) => {
|
|
96
|
-
try {
|
|
97
|
-
const decoded = jwtDecode(params.id_token);
|
|
98
|
-
const microsoftId = decoded.oid;
|
|
99
|
-
const email = decoded.preferred_username;
|
|
100
|
-
const name = decoded.name;
|
|
101
|
-
|
|
102
|
-
let client = await Client.findOne({ $or: [{ microsoftId }, { email }] });
|
|
103
|
-
if (!client) {
|
|
104
|
-
client = new Client({ email, name, microsoftId, roles: [] });
|
|
105
|
-
// No password for OAuth clients by schema
|
|
106
|
-
await client.save();
|
|
107
|
-
} else if (!client.microsoftId) {
|
|
108
|
-
client.microsoftId = microsoftId;
|
|
109
|
-
await client.save();
|
|
110
|
-
}
|
|
111
|
-
return done(null, client);
|
|
112
|
-
} catch (err) { return done(err); }
|
|
113
|
-
}
|
|
114
|
-
)
|
|
115
|
-
);
|
|
116
|
-
|
|
117
|
-
/* ── Google (Users) ─────────────────────────────────────── */
|
|
118
|
-
if (process.env.GOOGLE_CLIENT_ID && process.env.GOOGLE_CLIENT_SECRET && process.env.GOOGLE_CALLBACK_URL_USER) {
|
|
119
|
-
passport.use(
|
|
120
|
-
'google-user',
|
|
121
|
-
new GoogleStrategy(
|
|
122
|
-
{
|
|
123
|
-
clientID: process.env.GOOGLE_CLIENT_ID,
|
|
124
|
-
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
|
|
125
|
-
callbackURL: process.env.GOOGLE_CALLBACK_URL_USER
|
|
126
|
-
},
|
|
127
|
-
async (_at, _rt, profile, done) => {
|
|
128
|
-
try {
|
|
129
|
-
const email = profile.emails && profile.emails[0]?.value;
|
|
130
|
-
if (!email) return done(null, false);
|
|
131
|
-
|
|
132
|
-
let user = await User.findOne({ email });
|
|
133
|
-
if (!user) {
|
|
134
|
-
user = new User({
|
|
135
|
-
email,
|
|
136
|
-
name: profile.displayName,
|
|
137
|
-
tenantId: DEFAULT_TENANT_ID,
|
|
138
|
-
googleId: profile.id,
|
|
139
|
-
roles: [],
|
|
140
|
-
status: 'active'
|
|
141
|
-
});
|
|
142
|
-
await user.save();
|
|
143
|
-
} else {
|
|
144
|
-
let changed = false;
|
|
145
|
-
if (!user.googleId) { user.googleId = profile.id; changed = true; }
|
|
146
|
-
if (!user.tenantId) { user.tenantId = DEFAULT_TENANT_ID; changed = true; }
|
|
147
|
-
if (changed) await user.save();
|
|
148
|
-
}
|
|
149
|
-
return done(null, user);
|
|
150
|
-
} catch (err) { return done(err); }
|
|
151
|
-
}
|
|
152
|
-
)
|
|
153
|
-
);
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
/* ── Google (Clients) ───────────────────────────────────── */
|
|
157
|
-
if (process.env.GOOGLE_CLIENT_ID && process.env.GOOGLE_CLIENT_SECRET && process.env.GOOGLE_CALLBACK_URL_CLIENT) {
|
|
158
|
-
passport.use(
|
|
159
|
-
'google-client',
|
|
160
|
-
new GoogleStrategy(
|
|
161
|
-
{
|
|
162
|
-
clientID: process.env.GOOGLE_CLIENT_ID,
|
|
163
|
-
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
|
|
164
|
-
callbackURL: process.env.GOOGLE_CALLBACK_URL_CLIENT
|
|
165
|
-
},
|
|
166
|
-
async (_at, _rt, profile, done) => {
|
|
167
|
-
try {
|
|
168
|
-
const email = profile.emails && profile.emails[0]?.value;
|
|
169
|
-
if (!email) return done(null, false);
|
|
170
|
-
|
|
171
|
-
let client = await Client.findOne({ email });
|
|
172
|
-
if (!client) {
|
|
173
|
-
client = new Client({
|
|
174
|
-
email,
|
|
175
|
-
name: profile.displayName,
|
|
176
|
-
googleId: profile.id,
|
|
177
|
-
roles: []
|
|
178
|
-
});
|
|
179
|
-
await client.save();
|
|
180
|
-
} else if (!client.googleId) {
|
|
181
|
-
client.googleId = profile.id;
|
|
182
|
-
await client.save();
|
|
183
|
-
}
|
|
184
|
-
return done(null, client);
|
|
185
|
-
} catch (err) { return done(err); }
|
|
186
|
-
}
|
|
187
|
-
)
|
|
188
|
-
);
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
/* ── Facebook (Users) ───────────────────────────────────── */
|
|
192
|
-
if (process.env.FB_CLIENT_ID && process.env.FB_CLIENT_SECRET && process.env.FB_CALLBACK_URL_USER) {
|
|
193
|
-
passport.use(
|
|
194
|
-
'facebook-user',
|
|
195
|
-
new FacebookStrategy(
|
|
196
|
-
{
|
|
197
|
-
clientID: process.env.FB_CLIENT_ID,
|
|
198
|
-
clientSecret: process.env.FB_CLIENT_SECRET,
|
|
199
|
-
callbackURL: process.env.FB_CALLBACK_URL_USER,
|
|
200
|
-
profileFields: ['id', 'displayName', 'emails']
|
|
201
|
-
},
|
|
202
|
-
async (_at, _rt, profile, done) => {
|
|
203
|
-
try {
|
|
204
|
-
const email = profile.emails && profile.emails[0]?.value;
|
|
205
|
-
if (!email) return done(null, false);
|
|
206
|
-
|
|
207
|
-
let user = await User.findOne({ email });
|
|
208
|
-
if (!user) {
|
|
209
|
-
user = new User({
|
|
210
|
-
email,
|
|
211
|
-
name: profile.displayName,
|
|
212
|
-
tenantId: DEFAULT_TENANT_ID,
|
|
213
|
-
facebookId: profile.id,
|
|
214
|
-
roles: [],
|
|
215
|
-
status: 'active'
|
|
216
|
-
});
|
|
217
|
-
await user.save();
|
|
218
|
-
} else {
|
|
219
|
-
let changed = false;
|
|
220
|
-
if (!user.facebookId) { user.facebookId = profile.id; changed = true; }
|
|
221
|
-
if (!user.tenantId) { user.tenantId = DEFAULT_TENANT_ID; changed = true; }
|
|
222
|
-
if (changed) await user.save();
|
|
223
|
-
}
|
|
224
|
-
return done(null, user);
|
|
225
|
-
} catch (err) { return done(err); }
|
|
226
|
-
}
|
|
227
|
-
)
|
|
228
|
-
);
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
/* ── Facebook (Clients) ─────────────────────────────────── */
|
|
232
|
-
if (process.env.FB_CLIENT_ID && process.env.FB_CLIENT_SECRET && process.env.FB_CALLBACK_URL_CLIENT) {
|
|
233
|
-
passport.use(
|
|
234
|
-
'facebook-client',
|
|
235
|
-
new FacebookStrategy(
|
|
236
|
-
{
|
|
237
|
-
clientID: process.env.FB_CLIENT_ID,
|
|
238
|
-
clientSecret: process.env.FB_CLIENT_SECRET,
|
|
239
|
-
callbackURL: process.env.FB_CALLBACK_URL_CLIENT,
|
|
240
|
-
profileFields: ['id', 'displayName', 'emails']
|
|
241
|
-
},
|
|
242
|
-
async (_at, _rt, profile, done) => {
|
|
243
|
-
try {
|
|
244
|
-
const email = profile.emails && profile.emails[0]?.value;
|
|
245
|
-
if (!email) return done(null, false);
|
|
246
|
-
|
|
247
|
-
let client = await Client.findOne({ email });
|
|
248
|
-
if (!client) {
|
|
249
|
-
client = new Client({
|
|
250
|
-
email,
|
|
251
|
-
name: profile.displayName,
|
|
252
|
-
facebookId: profile.id,
|
|
253
|
-
roles: []
|
|
254
|
-
});
|
|
255
|
-
await client.save();
|
|
256
|
-
} else if (!client.facebookId) {
|
|
257
|
-
client.facebookId = profile.id;
|
|
258
|
-
await client.save();
|
|
259
|
-
}
|
|
260
|
-
return done(null, client);
|
|
261
|
-
} catch (err) { return done(err); }
|
|
262
|
-
}
|
|
263
|
-
)
|
|
264
|
-
);
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
/* ── Sessions (only if you use them) ────────────────────── */
|
|
268
|
-
passport.serializeUser((principal, done) => done(null, principal.id));
|
|
269
|
-
passport.deserializeUser(async (id, done) => {
|
|
270
|
-
try {
|
|
271
|
-
// Try Users, then Clients
|
|
272
|
-
let principal = await User.findById(id);
|
|
273
|
-
if (!principal) principal = await Client.findById(id);
|
|
274
|
-
done(null, principal);
|
|
275
|
-
} catch (err) {
|
|
276
|
-
done(err);
|
|
277
|
-
}
|
|
278
|
-
});
|
|
279
|
-
|
|
280
|
-
module.exports = passport;
|