@ciscode/authentication-kit 1.1.0 → 1.1.2

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.
Files changed (74) hide show
  1. package/README.md +57 -73
  2. package/dist/auth-kit.module.d.ts +7 -0
  3. package/dist/auth-kit.module.js +50 -0
  4. package/dist/config/db.config.d.ts +1 -0
  5. package/dist/config/db.config.js +22 -0
  6. package/dist/config/passport.config.d.ts +3 -0
  7. package/dist/config/passport.config.js +272 -0
  8. package/dist/controllers/admin.controller.d.ts +4 -0
  9. package/dist/controllers/admin.controller.js +59 -0
  10. package/dist/controllers/auth.controller.d.ts +23 -0
  11. package/dist/controllers/auth.controller.js +645 -0
  12. package/dist/controllers/password-reset.controller.d.ts +8 -0
  13. package/dist/controllers/password-reset.controller.js +146 -0
  14. package/dist/controllers/permissions.controller.d.ts +7 -0
  15. package/dist/controllers/permissions.controller.js +115 -0
  16. package/dist/controllers/roles.controller.d.ts +7 -0
  17. package/dist/controllers/roles.controller.js +113 -0
  18. package/dist/controllers/users.controller.d.ts +8 -0
  19. package/dist/controllers/users.controller.js +259 -0
  20. package/dist/index.d.ts +6 -0
  21. package/dist/index.js +14 -0
  22. package/dist/middleware/auth.guard.d.ts +4 -0
  23. package/dist/middleware/auth.guard.js +39 -0
  24. package/dist/middleware/authenticate.guard.d.ts +4 -0
  25. package/dist/middleware/authenticate.guard.js +44 -0
  26. package/dist/middleware/permission.guard.d.ts +4 -0
  27. package/dist/middleware/permission.guard.js +52 -0
  28. package/dist/middleware/tenant.guard.d.ts +4 -0
  29. package/dist/middleware/tenant.guard.js +39 -0
  30. package/dist/models/client.model.d.ts +54 -0
  31. package/dist/models/client.model.js +34 -0
  32. package/dist/models/permission.model.d.ts +19 -0
  33. package/dist/models/permission.model.js +17 -0
  34. package/dist/models/role.model.d.ts +33 -0
  35. package/dist/models/role.model.js +19 -0
  36. package/dist/models/tenant.model.d.ts +19 -0
  37. package/dist/models/tenant.model.js +15 -0
  38. package/dist/models/user.model.d.ts +63 -0
  39. package/dist/models/user.model.js +41 -0
  40. package/dist/standalone.d.ts +1 -0
  41. package/dist/standalone.js +12 -0
  42. package/dist/utils/helper.d.ts +1 -0
  43. package/dist/utils/helper.js +22 -0
  44. package/package.json +69 -43
  45. package/.github/workflows/ci .yml +0 -36
  46. package/.github/workflows/publish.yml +0 -30
  47. package/CODE_OF_CONDUCT +0 -38
  48. package/CONTRIBUTING.md +0 -40
  49. package/SECURITY +0 -31
  50. package/azure-pipelines.yml +0 -100
  51. package/src/config/db.config.js +0 -21
  52. package/src/config/passport.config.js +0 -280
  53. package/src/controllers/auth.controller.js +0 -566
  54. package/src/controllers/passwordReset.controller.js +0 -127
  55. package/src/controllers/permission.controller.js +0 -81
  56. package/src/controllers/roles.controller.js +0 -108
  57. package/src/controllers/user.controller.js +0 -283
  58. package/src/index.js +0 -32
  59. package/src/middleware/auth.middleware.js +0 -16
  60. package/src/middleware/authenticate.js +0 -25
  61. package/src/middleware/rbac.middleware.js +0 -24
  62. package/src/middleware/tenant.middleware.js +0 -16
  63. package/src/models/client.model.js +0 -39
  64. package/src/models/permission.model.js +0 -9
  65. package/src/models/role.model.js +0 -14
  66. package/src/models/tenant.model.js +0 -9
  67. package/src/models/user.model.js +0 -51
  68. package/src/routes/admin.routes.js +0 -8
  69. package/src/routes/auth.routes.js +0 -77
  70. package/src/routes/passwordReset.routes.js +0 -8
  71. package/src/routes/permission.routes.js +0 -17
  72. package/src/routes/roles.routes.js +0 -11
  73. package/src/routes/user.routes.js +0 -22
  74. package/src/utils/helper.js +0 -26
package/README.md CHANGED
@@ -1,48 +1,31 @@
1
- Auth Service (Express · JWT · Multi‑Tenant · RBAC)
2
- Internal package private to the company.
3
- This package is not published on npmjs. Install it only from the company’s Azure Artifacts feed using a project or user-level .npmrc.
1
+ Auth Service (NestJS, JWT, Multi-tenant, RBAC)
2
+ Internal package - private to the company.
3
+ This package is not published on npmjs. Install it only from the company Azure Artifacts feed using a project or user-level .npmrc.
4
4
 
5
- Authentication & authorization service for Node/Express apps.
6
- Provides local email/password auth with lockout, JWT access tokens + refresh, tenant scoping, RBAC, and optional Microsoft Entra (Azure AD) OAuth.
5
+ Authentication and authorization module for NestJS apps.
6
+ Provides local email/password auth with lockout, JWT access tokens and refresh, tenant scoping, RBAC, and optional OAuth (Microsoft Entra, Google, Facebook).
7
7
 
8
8
  Features
9
9
  Local auth (email/password) with account lockout policy.
10
10
  JWT access tokens (Bearer) and refresh endpoint (cookie or body).
11
11
  Multi-tenant scope on requests.
12
- RBAC (roles permission strings).
13
- Microsoft Entra (Azure AD) OAuth (optional).
12
+ RBAC (roles -> permission strings).
13
+ Microsoft Entra (Azure AD), Google, Facebook OAuth (optional).
14
14
  MongoDB/Mongoose models.
15
+
15
16
  Routes are mounted under:
16
17
 
17
18
  /api/auth (auth, password reset)
18
19
  /api/users (user admin)
19
20
  /api/auth/roles and /api/auth/permissions (RBAC)
20
- Installation (Azure Artifacts only)
21
- 1) Configure .npmrc
22
- Do not commit real tokens. Prefer ~/.npmrc or generate .npmrc in CI using secrets.
23
-
24
- For developers (user-level ~/.npmrc):
25
-
26
- registry=https://registry.npmjs.org/
27
-
28
- # Route @ciscodeapps scope to the private feed
29
- @ciscodeapps:registry=https://pkgs.dev.azure.com/CISCODEAPPS/Templates/_packaging/testfeed/npm/registry/
21
+ /api/admin (admin actions)
30
22
 
31
- //pkgs.dev.azure.com/CISCODEAPPS/Templates/_packaging/testfeed/npm/registry/:_authToken=${AZURE_ARTIFACTS_PAT}
32
- always-auth=true
33
- Set the token as an environment variable before installing:
23
+ Installation
34
24
 
35
- export AZURE_ARTIFACTS_PAT="<your PAT with Packaging:Read>"
36
- You can also use the username/_password form:
25
+ 1) Install the package
26
+ npm i @ciscode/authentication-kit
37
27
 
38
- //pkgs.dev.azure.com/...:username=AzureDevOps
39
- //pkgs.dev.azure.com/...:_password=${BASE64_PAT}
40
- //pkgs.dev.azure.com/...:email=not-used@localhost
41
- where BASE64_PAT=$(printf %s "$AZURE_ARTIFACTS_PAT" | base64).
42
-
43
- 2) Install the package
44
- npm i @ciscodeapps/auth-service
45
- 3) Required environment variables (host app)
28
+ 2) Required environment variables (host app)
46
29
  Create a .env in the host project:
47
30
 
48
31
  # Server
@@ -64,61 +47,59 @@ MAX_FAILED_LOGIN_ATTEMPTS=5
64
47
  ACCOUNT_LOCK_TIME_MINUTES=15
65
48
 
66
49
  # (Optional) Microsoft Entra ID (Azure AD)
67
- MICROSOFT_TENANT=organizations
50
+ MICROSOFT_TENANT_ID=common
68
51
  MICROSOFT_CLIENT_ID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
69
52
  MICROSOFT_CLIENT_SECRET=your-secret
70
53
  MICROSOFT_CALLBACK_URL=${BASE_URL}/api/auth/microsoft/callback
71
- Use inside an existing Express app
72
- Your package exports an Express app that already parses JSON, connects to Mongo, and mounts its routes. Just mount it:
73
54
 
74
- // server.js (host app)
75
- require('dotenv').config();
76
- const express = require('express');
77
- const authApp = require('@ciscodeapps/auth-service');
55
+ Use inside an existing Nest app
56
+ The module connects to Mongo on init and mounts its controllers.
57
+
58
+ // app.module.ts (host app)
59
+ import { Module } from '@nestjs/common';
60
+ import { AuthKitModule } from '@ciscode/authentication-kit';
61
+
62
+ @Module({
63
+ imports: [AuthKitModule]
64
+ })
65
+ export class AppModule {}
78
66
 
79
- const app = express();
80
- app.use(authApp); // exposes /api/auth, /api/users, /api/auth/roles, /api/auth/permissions
67
+ If you need to run it standalone, build and start the package:
81
68
 
82
- app.get('/health', (_, res) => res.json({ ok: true }));
83
- app.listen(process.env.PORT || 3000, () =>
84
- console.log('Host app on', process.env.PORT || 3000)
85
- );
86
- Prefer mounting the service. If you need to run it standalone, you can also start this package directly (it calls connectDB() on import).
69
+ npm run build
70
+ npm start
87
71
 
88
- What’s included (routes & behavior)
72
+ What is included (routes and behavior)
89
73
  Auth
90
- POST /api/auth/register Create a user (email/password).
91
- POST /api/auth/login Local login. On success, returns accessToken and may set a refreshToken httpOnly cookie.
92
- POST /api/auth/verify-otp – If OTP/step-up is enabled, verifies the code and completes login.
93
- POST /api/auth/refresh-token New access token from a valid refresh token (cookie or body).
94
- POST /api/auth/request-password-reset Sends a reset token (e.g., by email).
95
- PATCH /api/auth/reset-password – Consumes the reset token and sets a new password.
96
- GET /api/auth/microsoft → GET /api/auth/microsoft/callback – Optional Microsoft Entra OAuth; issues first-party tokens.
74
+ POST /api/auth/login - Local login. On success, returns accessToken and may set a refreshToken httpOnly cookie.
75
+ POST /api/auth/refresh-token - New access token from a valid refresh token (cookie or body).
76
+ POST /api/auth/request-password-reset - Sends a reset token (e.g., by email).
77
+ POST /api/auth/reset-password - Consumes the reset token and sets a new password.
78
+ GET /api/auth/microsoft - GET /api/auth/microsoft/callback - Optional Microsoft Entra OAuth; issues first-party tokens.
97
79
  Users
98
- GET /api/users List users (tenant-scoped, paginated).
99
- POST /api/users Create a user (requires permission).
80
+ GET /api/users - List users (tenant-scoped, paginated).
81
+ POST /api/users - Create a user.
100
82
  Additional CRUD endpoints as exposed by controllers.
101
- Roles & Permissions
102
- GET/POST /api/auth/roles Manage roles (name, tenantId, permissions: string[]).
103
- GET /api/auth/permissions List permission strings and metadata.
83
+ Roles and Permissions
84
+ GET/POST /api/auth/roles - Manage roles (name, tenantId, permissions: string[]).
85
+ GET /api/auth/permissions - List permission strings and metadata.
86
+
104
87
  Protecting your own routes (host app)
105
- const authenticate = require('@ciscodeapps/auth-service/src/middleware/authenticate'); // JWT
106
- const { hasPermission } = require('@ciscodeapps/auth-service/src/middleware/rbac.middleware'); // RBAC
107
-
108
- app.get('/reports',
109
- authenticate,
110
- hasPermission('reports:read'),
111
- (req, res) => res.json({ ok: true })
112
- );
88
+ import { UseGuards } from '@nestjs/common';
89
+ import { AuthenticateGuard, hasPermission } from '@ciscode/authentication-kit';
90
+
91
+ @UseGuards(AuthenticateGuard, hasPermission('reports:read'))
92
+ @Get('reports')
93
+ getReports() {
94
+ return { ok: true };
95
+ }
96
+
113
97
  Tenant scope comes from the JWT payload (e.g., tenantId) and is used inside controllers/guards to filter queries.
114
98
 
115
99
  Quick start (smoke tests)
116
- Start your host app:
117
-
118
- node server.js
119
- Register & Login
100
+ Start your host app, then create a user and log in:
120
101
 
121
- curl -X POST http://localhost:3000/api/auth/register \
102
+ curl -X POST http://localhost:3000/api/users \
122
103
  -H 'Content-Type: application/json' \
123
104
  -d '{"email":"a@b.com","password":"Secret123!","tenantId":"t-001","name":"Alice"}'
124
105
 
@@ -126,17 +107,20 @@ curl -X POST http://localhost:3000/api/auth/login \
126
107
  -H 'Content-Type: application/json' \
127
108
  -d '{"email":"a@b.com","password":"Secret123!","tenantId":"t-001"}'
128
109
  # => { "accessToken": "...", "refreshToken": "..." }
110
+
129
111
  Call a protected route
130
112
 
131
113
  ACCESS=<paste_access_token_here>
132
114
  curl http://localhost:3000/api/users -H "Authorization: Bearer $ACCESS"
115
+
133
116
  Refresh token
134
117
 
135
118
  curl -X POST http://localhost:3000/api/auth/refresh-token \
136
119
  -H 'Content-Type: application/json' \
137
120
  -d '{"refreshToken":"<paste_refresh_token_here>"}'
138
121
  # => { "accessToken": "..." }
139
- Microsoft OAuth (optional) - Visit: http://localhost:3000/api/auth/microsoft → complete sign-in.
122
+
123
+ Microsoft OAuth (optional) - Visit: http://localhost:3000/api/auth/microsoft to complete sign-in.
140
124
  - Callback: ${BASE_URL}/api/auth/microsoft/callback returns tokens (and may set the refresh cookie).
141
125
 
142
126
  CI/CD (Azure Pipelines)
@@ -151,7 +135,7 @@ CI/CD (Azure Pipelines)
151
135
 
152
136
  Security notes
153
137
  Never commit real PATs. Use env vars or CI secrets.
154
- Run behind HTTPS. Rotate JWT & refresh secrets periodically.
138
+ Run behind HTTPS. Rotate JWT and refresh secrets periodically.
155
139
  Limit login attempts; log auth events for auditing.
156
140
  License
157
- Internal Company proprietary.
141
+ Internal - Company proprietary.
@@ -0,0 +1,7 @@
1
+ import 'dotenv/config';
2
+ import { MiddlewareConsumer, NestModule, OnModuleDestroy, OnModuleInit } from '@nestjs/common';
3
+ export declare class AuthKitModule implements NestModule, OnModuleInit, OnModuleDestroy {
4
+ onModuleInit(): Promise<void>;
5
+ onModuleDestroy(): Promise<void>;
6
+ configure(consumer: MiddlewareConsumer): void;
7
+ }
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __importDefault = (this && this.__importDefault) || function (mod) {
9
+ return (mod && mod.__esModule) ? mod : { "default": mod };
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.AuthKitModule = void 0;
13
+ require("dotenv/config");
14
+ const common_1 = require("@nestjs/common");
15
+ const passport_config_1 = __importDefault(require("./config/passport.config"));
16
+ const cookie_parser_1 = __importDefault(require("cookie-parser"));
17
+ const mongoose_1 = __importDefault(require("mongoose"));
18
+ const db_config_1 = require("./config/db.config");
19
+ const auth_controller_1 = require("./controllers/auth.controller");
20
+ const password_reset_controller_1 = require("./controllers/password-reset.controller");
21
+ const users_controller_1 = require("./controllers/users.controller");
22
+ const roles_controller_1 = require("./controllers/roles.controller");
23
+ const permissions_controller_1 = require("./controllers/permissions.controller");
24
+ const admin_controller_1 = require("./controllers/admin.controller");
25
+ let AuthKitModule = class AuthKitModule {
26
+ async onModuleInit() {
27
+ await (0, db_config_1.connectDB)();
28
+ }
29
+ async onModuleDestroy() {
30
+ await mongoose_1.default.disconnect();
31
+ }
32
+ configure(consumer) {
33
+ consumer
34
+ .apply((0, cookie_parser_1.default)(), passport_config_1.default.initialize())
35
+ .forRoutes({ path: '*', method: common_1.RequestMethod.ALL });
36
+ }
37
+ };
38
+ exports.AuthKitModule = AuthKitModule;
39
+ exports.AuthKitModule = AuthKitModule = __decorate([
40
+ (0, common_1.Module)({
41
+ controllers: [
42
+ auth_controller_1.AuthController,
43
+ password_reset_controller_1.PasswordResetController,
44
+ users_controller_1.UsersController,
45
+ roles_controller_1.RolesController,
46
+ permissions_controller_1.PermissionsController,
47
+ admin_controller_1.AdminController,
48
+ ],
49
+ })
50
+ ], AuthKitModule);
@@ -0,0 +1 @@
1
+ export declare function connectDB(): Promise<void>;
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.connectDB = connectDB;
7
+ const mongoose_1 = __importDefault(require("mongoose"));
8
+ mongoose_1.default.set('strictQuery', false);
9
+ async function connectDB() {
10
+ try {
11
+ const mongoURI = process.env.MONGO_URI_T;
12
+ if (!mongoURI) {
13
+ throw new Error('MONGO_URI is not defined in the environment variables.');
14
+ }
15
+ await mongoose_1.default.connect(mongoURI);
16
+ console.log('MongoDB Connected...');
17
+ }
18
+ catch (error) {
19
+ console.error('MongoDB Connection Error:', error);
20
+ process.exit(1);
21
+ }
22
+ }
@@ -0,0 +1,3 @@
1
+ import passport from 'passport';
2
+ import 'dotenv/config';
3
+ export default passport;
@@ -0,0 +1,272 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const passport_1 = __importDefault(require("passport"));
7
+ const passport_local_1 = require("passport-local");
8
+ const passport_azure_ad_oauth2_1 = require("passport-azure-ad-oauth2");
9
+ const passport_google_oauth20_1 = require("passport-google-oauth20");
10
+ const passport_facebook_1 = require("passport-facebook");
11
+ const bcryptjs_1 = __importDefault(require("bcryptjs"));
12
+ const jsonwebtoken_1 = require("jsonwebtoken");
13
+ const user_model_1 = __importDefault(require("../models/user.model"));
14
+ const client_model_1 = __importDefault(require("../models/client.model"));
15
+ require("dotenv/config");
16
+ const MAX_FAILED = parseInt(process.env.MAX_FAILED_LOGIN_ATTEMPTS || '', 10) || 3;
17
+ const LOCK_TIME_MIN = parseInt(process.env.ACCOUNT_LOCK_TIME_MINUTES || '', 10) || 15;
18
+ const LOCK_TIME_MS = LOCK_TIME_MIN * 60 * 1000;
19
+ const DEFAULT_TENANT_ID = process.env.DEFAULT_TENANT_ID || 'social-staff';
20
+ passport_1.default.use(new passport_local_1.Strategy({ usernameField: 'email', passwordField: 'password', passReqToCallback: true }, async (req, email, password, done) => {
21
+ try {
22
+ const query = { email };
23
+ if (req.body.tenantId)
24
+ query.tenantId = String(req.body.tenantId).trim();
25
+ const user = await user_model_1.default.findOne(query);
26
+ if (!user)
27
+ return done(null, false, { message: 'Incorrect email (or tenant).' });
28
+ if (user.lockUntil && user.lockUntil > Date.now()) {
29
+ return done(null, false, { message: `Account locked until ${new Date(user.lockUntil).toLocaleString()}.` });
30
+ }
31
+ const ok = await bcryptjs_1.default.compare(password, user.password);
32
+ if (!ok) {
33
+ user.failedLoginAttempts += 1;
34
+ if (user.failedLoginAttempts >= MAX_FAILED)
35
+ user.lockUntil = Date.now() + LOCK_TIME_MS;
36
+ await user.save();
37
+ return done(null, false, { message: 'Incorrect password.' });
38
+ }
39
+ user.failedLoginAttempts = 0;
40
+ user.lockUntil = undefined;
41
+ await user.save();
42
+ return done(null, user);
43
+ }
44
+ catch (err) {
45
+ return done(err);
46
+ }
47
+ }));
48
+ passport_1.default.use(new passport_azure_ad_oauth2_1.Strategy({
49
+ clientID: process.env.MICROSOFT_CLIENT_ID,
50
+ clientSecret: process.env.MICROSOFT_CLIENT_SECRET,
51
+ callbackURL: process.env.MICROSOFT_CALLBACK_URL,
52
+ }, async (_at, _rt, params, _profile, done) => {
53
+ try {
54
+ const decoded = (0, jsonwebtoken_1.decode)(params.id_token);
55
+ const microsoftId = decoded.oid;
56
+ const email = decoded.preferred_username;
57
+ const name = decoded.name;
58
+ const tenantId = decoded.tid;
59
+ let user = await user_model_1.default.findOne({ $or: [{ microsoftId }, { email }] });
60
+ if (!user) {
61
+ user = new user_model_1.default({ email, name, tenantId, microsoftId, roles: [], status: 'active' });
62
+ await user.save();
63
+ }
64
+ else {
65
+ let changed = false;
66
+ if (!user.microsoftId) {
67
+ user.microsoftId = microsoftId;
68
+ changed = true;
69
+ }
70
+ if (!user.tenantId) {
71
+ user.tenantId = tenantId;
72
+ changed = true;
73
+ }
74
+ if (changed)
75
+ await user.save();
76
+ }
77
+ return done(null, user);
78
+ }
79
+ catch (err) {
80
+ return done(err);
81
+ }
82
+ }));
83
+ passport_1.default.use('azure_ad_oauth2_client', new passport_azure_ad_oauth2_1.Strategy({
84
+ clientID: process.env.MICROSOFT_CLIENT_ID_CLIENT || process.env.MICROSOFT_CLIENT_ID,
85
+ clientSecret: process.env.MICROSOFT_CLIENT_SECRET_CLIENT || process.env.MICROSOFT_CLIENT_SECRET,
86
+ callbackURL: process.env.MICROSOFT_CALLBACK_URL_CLIENT,
87
+ }, async (_at, _rt, params, _profile, done) => {
88
+ try {
89
+ const decoded = (0, jsonwebtoken_1.decode)(params.id_token);
90
+ const microsoftId = decoded.oid;
91
+ const email = decoded.preferred_username;
92
+ const name = decoded.name;
93
+ let client = await client_model_1.default.findOne({ $or: [{ microsoftId }, { email }] });
94
+ if (!client) {
95
+ client = new client_model_1.default({ email, name, microsoftId, roles: [] });
96
+ await client.save();
97
+ }
98
+ else if (!client.microsoftId) {
99
+ client.microsoftId = microsoftId;
100
+ await client.save();
101
+ }
102
+ return done(null, client);
103
+ }
104
+ catch (err) {
105
+ return done(err);
106
+ }
107
+ }));
108
+ if (process.env.GOOGLE_CLIENT_ID && process.env.GOOGLE_CLIENT_SECRET && process.env.GOOGLE_CALLBACK_URL_USER) {
109
+ passport_1.default.use('google-user', new passport_google_oauth20_1.Strategy({
110
+ clientID: process.env.GOOGLE_CLIENT_ID,
111
+ clientSecret: process.env.GOOGLE_CLIENT_SECRET,
112
+ callbackURL: process.env.GOOGLE_CALLBACK_URL_USER
113
+ }, async (_at, _rt, profile, done) => {
114
+ var _a;
115
+ try {
116
+ const email = profile.emails && ((_a = profile.emails[0]) === null || _a === void 0 ? void 0 : _a.value);
117
+ if (!email)
118
+ return done(null, false);
119
+ let user = await user_model_1.default.findOne({ email });
120
+ if (!user) {
121
+ user = new user_model_1.default({
122
+ email,
123
+ name: profile.displayName,
124
+ tenantId: DEFAULT_TENANT_ID,
125
+ googleId: profile.id,
126
+ roles: [],
127
+ status: 'active'
128
+ });
129
+ await user.save();
130
+ }
131
+ else {
132
+ let changed = false;
133
+ if (!user.googleId) {
134
+ user.googleId = profile.id;
135
+ changed = true;
136
+ }
137
+ if (!user.tenantId) {
138
+ user.tenantId = DEFAULT_TENANT_ID;
139
+ changed = true;
140
+ }
141
+ if (changed)
142
+ await user.save();
143
+ }
144
+ return done(null, user);
145
+ }
146
+ catch (err) {
147
+ return done(err);
148
+ }
149
+ }));
150
+ }
151
+ if (process.env.GOOGLE_CLIENT_ID && process.env.GOOGLE_CLIENT_SECRET && process.env.GOOGLE_CALLBACK_URL_CLIENT) {
152
+ passport_1.default.use('google-client', new passport_google_oauth20_1.Strategy({
153
+ clientID: process.env.GOOGLE_CLIENT_ID,
154
+ clientSecret: process.env.GOOGLE_CLIENT_SECRET,
155
+ callbackURL: process.env.GOOGLE_CALLBACK_URL_CLIENT
156
+ }, async (_at, _rt, profile, done) => {
157
+ var _a;
158
+ try {
159
+ const email = profile.emails && ((_a = profile.emails[0]) === null || _a === void 0 ? void 0 : _a.value);
160
+ if (!email)
161
+ return done(null, false);
162
+ let client = await client_model_1.default.findOne({ email });
163
+ if (!client) {
164
+ client = new client_model_1.default({
165
+ email,
166
+ name: profile.displayName,
167
+ googleId: profile.id,
168
+ roles: []
169
+ });
170
+ await client.save();
171
+ }
172
+ else if (!client.googleId) {
173
+ client.googleId = profile.id;
174
+ await client.save();
175
+ }
176
+ return done(null, client);
177
+ }
178
+ catch (err) {
179
+ return done(err);
180
+ }
181
+ }));
182
+ }
183
+ if (process.env.FB_CLIENT_ID && process.env.FB_CLIENT_SECRET && process.env.FB_CALLBACK_URL_USER) {
184
+ passport_1.default.use('facebook-user', new passport_facebook_1.Strategy({
185
+ clientID: process.env.FB_CLIENT_ID,
186
+ clientSecret: process.env.FB_CLIENT_SECRET,
187
+ callbackURL: process.env.FB_CALLBACK_URL_USER,
188
+ profileFields: ['id', 'displayName', 'emails']
189
+ }, async (_at, _rt, profile, done) => {
190
+ var _a;
191
+ try {
192
+ const email = profile.emails && ((_a = profile.emails[0]) === null || _a === void 0 ? void 0 : _a.value);
193
+ if (!email)
194
+ return done(null, false);
195
+ let user = await user_model_1.default.findOne({ email });
196
+ if (!user) {
197
+ user = new user_model_1.default({
198
+ email,
199
+ name: profile.displayName,
200
+ tenantId: DEFAULT_TENANT_ID,
201
+ facebookId: profile.id,
202
+ roles: [],
203
+ status: 'active'
204
+ });
205
+ await user.save();
206
+ }
207
+ else {
208
+ let changed = false;
209
+ if (!user.facebookId) {
210
+ user.facebookId = profile.id;
211
+ changed = true;
212
+ }
213
+ if (!user.tenantId) {
214
+ user.tenantId = DEFAULT_TENANT_ID;
215
+ changed = true;
216
+ }
217
+ if (changed)
218
+ await user.save();
219
+ }
220
+ return done(null, user);
221
+ }
222
+ catch (err) {
223
+ return done(err);
224
+ }
225
+ }));
226
+ }
227
+ if (process.env.FB_CLIENT_ID && process.env.FB_CLIENT_SECRET && process.env.FB_CALLBACK_URL_CLIENT) {
228
+ passport_1.default.use('facebook-client', new passport_facebook_1.Strategy({
229
+ clientID: process.env.FB_CLIENT_ID,
230
+ clientSecret: process.env.FB_CLIENT_SECRET,
231
+ callbackURL: process.env.FB_CALLBACK_URL_CLIENT,
232
+ profileFields: ['id', 'displayName', 'emails']
233
+ }, async (_at, _rt, profile, done) => {
234
+ var _a;
235
+ try {
236
+ const email = profile.emails && ((_a = profile.emails[0]) === null || _a === void 0 ? void 0 : _a.value);
237
+ if (!email)
238
+ return done(null, false);
239
+ let client = await client_model_1.default.findOne({ email });
240
+ if (!client) {
241
+ client = new client_model_1.default({
242
+ email,
243
+ name: profile.displayName,
244
+ facebookId: profile.id,
245
+ roles: []
246
+ });
247
+ await client.save();
248
+ }
249
+ else if (!client.facebookId) {
250
+ client.facebookId = profile.id;
251
+ await client.save();
252
+ }
253
+ return done(null, client);
254
+ }
255
+ catch (err) {
256
+ return done(err);
257
+ }
258
+ }));
259
+ }
260
+ passport_1.default.serializeUser((principal, done) => done(null, principal.id));
261
+ passport_1.default.deserializeUser(async (id, done) => {
262
+ try {
263
+ let principal = await user_model_1.default.findById(id);
264
+ if (!principal)
265
+ principal = await client_model_1.default.findById(id);
266
+ done(null, principal);
267
+ }
268
+ catch (err) {
269
+ done(err);
270
+ }
271
+ });
272
+ exports.default = passport_1.default;
@@ -0,0 +1,4 @@
1
+ import type { Request, Response } from 'express';
2
+ export declare class AdminController {
3
+ suspendUser(req: Request, res: Response): Promise<Response<any, Record<string, any>>>;
4
+ }
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
12
+ return function (target, key) { decorator(target, key, paramIndex); }
13
+ };
14
+ var __importDefault = (this && this.__importDefault) || function (mod) {
15
+ return (mod && mod.__esModule) ? mod : { "default": mod };
16
+ };
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ exports.AdminController = void 0;
19
+ const common_1 = require("@nestjs/common");
20
+ const user_model_1 = __importDefault(require("../models/user.model"));
21
+ const authenticate_guard_1 = require("../middleware/authenticate.guard");
22
+ let AdminController = class AdminController {
23
+ async suspendUser(req, res) {
24
+ try {
25
+ if (!req.user || !req.user.roles) {
26
+ return res.status(403).json({ message: 'Access denied. Superadmin privileges required.' });
27
+ }
28
+ if (!req.user.roles.includes('superadmin')) {
29
+ return res.status(403).json({ message: 'Access denied. Superadmin privileges required.' });
30
+ }
31
+ const { id } = req.params;
32
+ if (!id) {
33
+ return res.status(400).json({ message: 'User ID is required in the URL.' });
34
+ }
35
+ const updatedUser = await user_model_1.default.findByIdAndUpdate(id, { status: 'suspended' }, { new: true });
36
+ if (!updatedUser) {
37
+ return res.status(404).json({ message: 'User not found.' });
38
+ }
39
+ return res.status(200).json({ message: 'User suspended successfully.', user: updatedUser });
40
+ }
41
+ catch (error) {
42
+ console.error('Error suspending user:', error);
43
+ return res.status(500).json({ message: 'Server error', error: error.message });
44
+ }
45
+ }
46
+ };
47
+ exports.AdminController = AdminController;
48
+ __decorate([
49
+ (0, common_1.Put)(':id/suspend'),
50
+ __param(0, (0, common_1.Req)()),
51
+ __param(1, (0, common_1.Res)()),
52
+ __metadata("design:type", Function),
53
+ __metadata("design:paramtypes", [Object, Object]),
54
+ __metadata("design:returntype", Promise)
55
+ ], AdminController.prototype, "suspendUser", null);
56
+ exports.AdminController = AdminController = __decorate([
57
+ (0, common_1.UseGuards)(authenticate_guard_1.AuthenticateGuard),
58
+ (0, common_1.Controller)('api/admin')
59
+ ], AdminController);
@@ -0,0 +1,23 @@
1
+ import type { Request, Response, NextFunction } from 'express';
2
+ export declare class AuthController {
3
+ private issueTokensAndRespond;
4
+ private respondWebOrMobile;
5
+ registerClient(req: Request, res: Response): Promise<Response<any, Record<string, any>>>;
6
+ clientLogin(req: Request, res: Response): Promise<Response<any, Record<string, any>>>;
7
+ localLogin(req: Request, res: Response, next: NextFunction): any;
8
+ microsoftLogin(req: Request, res: Response, next: NextFunction): any;
9
+ microsoftCallback(req: Request, res: Response, next: NextFunction): void;
10
+ microsoftExchange(req: Request, res: Response): Promise<Response<any, Record<string, any>>>;
11
+ googleUserLogin(req: Request, res: Response, next: NextFunction): any;
12
+ googleUserCallback(req: Request, res: Response, next: NextFunction): void;
13
+ googleClientLogin(req: Request, res: Response, next: NextFunction): any;
14
+ googleClientCallback(req: Request, res: Response, next: NextFunction): void;
15
+ googleExchange(req: Request, res: Response): Promise<Response<any, Record<string, any>>>;
16
+ facebookUserLogin(req: Request, res: Response, next: NextFunction): any;
17
+ facebookUserCallback(req: Request, res: Response, next: NextFunction): void;
18
+ facebookClientLogin(req: Request, res: Response, next: NextFunction): any;
19
+ facebookClientCallback(req: Request, res: Response, next: NextFunction): void;
20
+ microsoftClientLogin(req: Request, res: Response, next: NextFunction): any;
21
+ microsoftClientCallback(req: Request, res: Response, next: NextFunction): void;
22
+ refreshToken(req: Request, res: Response): Promise<Response<any, Record<string, any>>>;
23
+ }