@ciscode/authentication-kit 1.1.6 → 1.2.0
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 +455 -120
- package/dist/auth-kit.module.d.ts +6 -4
- package/dist/auth-kit.module.js +64 -13
- package/dist/config/passport.config.d.ts +2 -1
- package/dist/config/passport.config.js +64 -241
- package/dist/controllers/auth.controller.d.ts +35 -19
- package/dist/controllers/auth.controller.js +155 -488
- package/dist/controllers/permissions.controller.d.ts +10 -5
- package/dist/controllers/permissions.controller.js +40 -76
- package/dist/controllers/roles.controller.d.ts +11 -5
- package/dist/controllers/roles.controller.js +49 -66
- package/dist/controllers/users.controller.d.ts +15 -7
- package/dist/controllers/users.controller.js +52 -227
- package/dist/dtos/auth/forgot-password.dto.d.ts +3 -0
- package/dist/dtos/auth/forgot-password.dto.js +20 -0
- package/dist/dtos/auth/login.dto.d.ts +4 -0
- package/dist/dtos/auth/login.dto.js +24 -0
- package/dist/dtos/auth/refresh-token.dto.d.ts +3 -0
- package/dist/dtos/auth/refresh-token.dto.js +21 -0
- package/dist/dtos/auth/register.dto.d.ts +13 -0
- package/dist/dtos/auth/register.dto.js +56 -0
- package/dist/dtos/auth/resend-verification.dto.d.ts +3 -0
- package/dist/dtos/auth/resend-verification.dto.js +20 -0
- package/dist/dtos/auth/reset-password.dto.d.ts +4 -0
- package/dist/dtos/auth/reset-password.dto.js +25 -0
- package/dist/dtos/auth/update-user-role.dto.d.ts +3 -0
- package/dist/dtos/auth/update-user-role.dto.js +21 -0
- package/dist/dtos/auth/verify-email.dto.d.ts +3 -0
- package/dist/dtos/auth/verify-email.dto.js +20 -0
- package/dist/dtos/permission/create-permission.dto.d.ts +4 -0
- package/dist/dtos/permission/create-permission.dto.js +25 -0
- package/dist/dtos/permission/update-permission.dto.d.ts +4 -0
- package/dist/dtos/permission/update-permission.dto.js +26 -0
- package/dist/dtos/role/create-role.dto.d.ts +4 -0
- package/dist/dtos/role/create-role.dto.js +26 -0
- package/dist/dtos/role/update-role.dto.d.ts +7 -0
- package/dist/dtos/role/update-role.dto.js +35 -0
- package/dist/index.d.ts +5 -2
- package/dist/index.js +11 -5
- package/dist/middleware/admin.decorator.d.ts +1 -0
- package/dist/middleware/admin.decorator.js +8 -0
- package/dist/middleware/admin.guard.d.ts +7 -0
- package/dist/middleware/admin.guard.js +35 -0
- package/dist/middleware/authenticate.guard.d.ts +5 -1
- package/dist/middleware/authenticate.guard.js +35 -8
- package/dist/middleware/role.guard.d.ts +4 -0
- package/dist/middleware/role.guard.js +29 -0
- package/dist/models/permission.model.d.ts +8 -16
- package/dist/models/permission.model.js +25 -14
- package/dist/models/role.model.d.ts +9 -28
- package/dist/models/role.model.js +26 -14
- package/dist/models/user.model.d.ts +22 -64
- package/dist/models/user.model.js +82 -41
- package/dist/repositories/permission.repository.d.ts +34 -0
- package/dist/repositories/permission.repository.js +47 -0
- package/dist/repositories/role.repository.d.ts +39 -0
- package/dist/repositories/role.repository.js +50 -0
- package/dist/repositories/user.repository.d.ts +57 -0
- package/dist/repositories/user.repository.js +71 -0
- package/dist/services/admin-role.service.d.ts +7 -0
- package/dist/services/admin-role.service.js +33 -0
- package/dist/services/auth.service.d.ts +49 -0
- package/dist/services/auth.service.js +219 -0
- package/dist/services/mail.service.d.ts +5 -0
- package/dist/services/mail.service.js +39 -0
- package/dist/services/oauth.service.d.ts +32 -0
- package/dist/services/oauth.service.js +138 -0
- package/dist/services/permissions.service.d.ts +19 -0
- package/dist/services/permissions.service.js +44 -0
- package/dist/services/roles.service.d.ts +23 -0
- package/dist/services/roles.service.js +57 -0
- package/dist/services/seed.service.d.ts +11 -0
- package/dist/services/seed.service.js +50 -0
- package/dist/services/users.service.d.ts +30 -0
- package/dist/services/users.service.js +81 -0
- package/package.json +31 -21
- package/dist/config/db.config.d.ts +0 -1
- package/dist/config/db.config.js +0 -22
- package/dist/controllers/admin.controller.d.ts +0 -4
- package/dist/controllers/admin.controller.js +0 -59
- package/dist/controllers/password-reset.controller.d.ts +0 -8
- package/dist/controllers/password-reset.controller.js +0 -146
- package/dist/middleware/auth.guard.d.ts +0 -4
- package/dist/middleware/auth.guard.js +0 -39
- package/dist/middleware/permission.guard.d.ts +0 -4
- package/dist/middleware/permission.guard.js +0 -52
- package/dist/models/client.model.d.ts +0 -54
- package/dist/models/client.model.js +0 -37
- package/dist/models/tenant.model.d.ts +0 -19
- package/dist/models/tenant.model.js +0 -15
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
19
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
20
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
21
|
+
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;
|
|
22
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
23
|
+
};
|
|
24
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
25
|
+
var ownKeys = function(o) {
|
|
26
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
27
|
+
var ar = [];
|
|
28
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
29
|
+
return ar;
|
|
30
|
+
};
|
|
31
|
+
return ownKeys(o);
|
|
32
|
+
};
|
|
33
|
+
return function (mod) {
|
|
34
|
+
if (mod && mod.__esModule) return mod;
|
|
35
|
+
var result = {};
|
|
36
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
37
|
+
__setModuleDefault(result, mod);
|
|
38
|
+
return result;
|
|
39
|
+
};
|
|
40
|
+
})();
|
|
41
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
42
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
43
|
+
};
|
|
44
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
45
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
46
|
+
};
|
|
47
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
48
|
+
exports.AuthService = void 0;
|
|
49
|
+
const common_1 = require("@nestjs/common");
|
|
50
|
+
const bcryptjs_1 = __importDefault(require("bcryptjs"));
|
|
51
|
+
const jwt = __importStar(require("jsonwebtoken"));
|
|
52
|
+
const user_repository_1 = require("../repositories/user.repository");
|
|
53
|
+
const mail_service_1 = require("./mail.service");
|
|
54
|
+
const role_repository_1 = require("../repositories/role.repository");
|
|
55
|
+
let AuthService = class AuthService {
|
|
56
|
+
constructor(users, mail, roles) {
|
|
57
|
+
this.users = users;
|
|
58
|
+
this.mail = mail;
|
|
59
|
+
this.roles = roles;
|
|
60
|
+
}
|
|
61
|
+
resolveExpiry(value, fallback) {
|
|
62
|
+
return (value || fallback);
|
|
63
|
+
}
|
|
64
|
+
signAccessToken(payload) {
|
|
65
|
+
const expiresIn = this.resolveExpiry(process.env.JWT_ACCESS_TOKEN_EXPIRES_IN, '15m');
|
|
66
|
+
return jwt.sign(payload, this.getEnv('JWT_SECRET'), { expiresIn });
|
|
67
|
+
}
|
|
68
|
+
signRefreshToken(payload) {
|
|
69
|
+
const expiresIn = this.resolveExpiry(process.env.JWT_REFRESH_TOKEN_EXPIRES_IN, '7d');
|
|
70
|
+
return jwt.sign(payload, this.getEnv('JWT_REFRESH_SECRET'), { expiresIn });
|
|
71
|
+
}
|
|
72
|
+
signEmailToken(payload) {
|
|
73
|
+
const expiresIn = this.resolveExpiry(process.env.JWT_EMAIL_TOKEN_EXPIRES_IN, '1d');
|
|
74
|
+
return jwt.sign(payload, this.getEnv('JWT_EMAIL_SECRET'), { expiresIn });
|
|
75
|
+
}
|
|
76
|
+
signResetToken(payload) {
|
|
77
|
+
const expiresIn = this.resolveExpiry(process.env.JWT_RESET_TOKEN_EXPIRES_IN, '1h');
|
|
78
|
+
return jwt.sign(payload, this.getEnv('JWT_RESET_SECRET'), { expiresIn });
|
|
79
|
+
}
|
|
80
|
+
async buildTokenPayload(userId) {
|
|
81
|
+
const user = await this.users.findByIdWithRolesAndPermissions(userId);
|
|
82
|
+
if (!user)
|
|
83
|
+
throw new Error('User not found.');
|
|
84
|
+
const roles = (user.roles || []).map((r) => r._id.toString());
|
|
85
|
+
const permissions = (user.roles || [])
|
|
86
|
+
.flatMap((r) => (r.permissions || []).map((p) => p.name))
|
|
87
|
+
.filter(Boolean);
|
|
88
|
+
return { sub: user._id.toString(), roles, permissions };
|
|
89
|
+
}
|
|
90
|
+
getEnv(name) {
|
|
91
|
+
const v = process.env[name];
|
|
92
|
+
if (!v)
|
|
93
|
+
throw new Error(`${name} is not set`);
|
|
94
|
+
return v;
|
|
95
|
+
}
|
|
96
|
+
async issueTokensForUser(userId) {
|
|
97
|
+
const payload = await this.buildTokenPayload(userId);
|
|
98
|
+
const accessToken = this.signAccessToken(payload);
|
|
99
|
+
const refreshToken = this.signRefreshToken({ sub: userId, purpose: 'refresh' });
|
|
100
|
+
return { accessToken, refreshToken };
|
|
101
|
+
}
|
|
102
|
+
async register(dto) {
|
|
103
|
+
if (await this.users.findByEmail(dto.email))
|
|
104
|
+
throw new Error('Email already in use.');
|
|
105
|
+
if (await this.users.findByUsername(dto.username))
|
|
106
|
+
throw new Error('Username already in use.');
|
|
107
|
+
if (dto.phoneNumber && (await this.users.findByPhone(dto.phoneNumber))) {
|
|
108
|
+
throw new Error('Phone already in use.');
|
|
109
|
+
}
|
|
110
|
+
const salt = await bcryptjs_1.default.genSalt(10);
|
|
111
|
+
const hashed = await bcryptjs_1.default.hash(dto.password, salt);
|
|
112
|
+
const userRole = await this.roles.findByName('user');
|
|
113
|
+
if (!userRole)
|
|
114
|
+
throw new Error('Default role not seeded.');
|
|
115
|
+
const user = await this.users.create({
|
|
116
|
+
fullname: dto.fullname,
|
|
117
|
+
username: dto.username,
|
|
118
|
+
email: dto.email,
|
|
119
|
+
phoneNumber: dto.phoneNumber,
|
|
120
|
+
avatar: dto.avatar,
|
|
121
|
+
password: hashed,
|
|
122
|
+
roles: [userRole._id],
|
|
123
|
+
isVerified: false,
|
|
124
|
+
isBanned: false,
|
|
125
|
+
passwordChangedAt: new Date()
|
|
126
|
+
});
|
|
127
|
+
const emailToken = this.signEmailToken({ sub: user._id.toString(), purpose: 'verify' });
|
|
128
|
+
await this.mail.sendVerificationEmail(user.email, emailToken);
|
|
129
|
+
return { id: user._id, email: user.email };
|
|
130
|
+
}
|
|
131
|
+
async verifyEmail(token) {
|
|
132
|
+
const decoded = jwt.verify(token, this.getEnv('JWT_EMAIL_SECRET'));
|
|
133
|
+
if (decoded.purpose !== 'verify')
|
|
134
|
+
throw new Error('Invalid token purpose.');
|
|
135
|
+
const user = await this.users.findById(decoded.sub);
|
|
136
|
+
if (!user)
|
|
137
|
+
throw new Error('User not found.');
|
|
138
|
+
if (user.isVerified)
|
|
139
|
+
return { ok: true };
|
|
140
|
+
user.isVerified = true;
|
|
141
|
+
await user.save();
|
|
142
|
+
return { ok: true };
|
|
143
|
+
}
|
|
144
|
+
async resendVerification(email) {
|
|
145
|
+
const user = await this.users.findByEmail(email);
|
|
146
|
+
if (!user || user.isVerified)
|
|
147
|
+
return { ok: true };
|
|
148
|
+
const emailToken = this.signEmailToken({ sub: user._id.toString(), purpose: 'verify' });
|
|
149
|
+
await this.mail.sendVerificationEmail(user.email, emailToken);
|
|
150
|
+
return { ok: true };
|
|
151
|
+
}
|
|
152
|
+
async login(dto) {
|
|
153
|
+
const user = await this.users.findByEmailWithPassword(dto.email);
|
|
154
|
+
if (!user)
|
|
155
|
+
throw new Error('Invalid credentials.');
|
|
156
|
+
if (user.isBanned)
|
|
157
|
+
throw new Error('Account banned.');
|
|
158
|
+
if (!user.isVerified)
|
|
159
|
+
throw new Error('Email not verified.');
|
|
160
|
+
const ok = await bcryptjs_1.default.compare(dto.password, user.password);
|
|
161
|
+
if (!ok)
|
|
162
|
+
throw new Error('Invalid credentials.');
|
|
163
|
+
const payload = await this.buildTokenPayload(user._id.toString());
|
|
164
|
+
const accessToken = this.signAccessToken(payload);
|
|
165
|
+
const refreshToken = this.signRefreshToken({ sub: user._id.toString(), purpose: 'refresh' });
|
|
166
|
+
return { accessToken, refreshToken };
|
|
167
|
+
}
|
|
168
|
+
async refresh(refreshToken) {
|
|
169
|
+
const decoded = jwt.verify(refreshToken, this.getEnv('JWT_REFRESH_SECRET'));
|
|
170
|
+
if (decoded.purpose !== 'refresh')
|
|
171
|
+
throw new Error('Invalid token purpose.');
|
|
172
|
+
const user = await this.users.findById(decoded.sub);
|
|
173
|
+
if (!user)
|
|
174
|
+
throw new Error('User not found.');
|
|
175
|
+
if (user.isBanned)
|
|
176
|
+
throw new Error('Account banned.');
|
|
177
|
+
if (!user.isVerified)
|
|
178
|
+
throw new Error('Email not verified.');
|
|
179
|
+
if (user.passwordChangedAt && decoded.iat * 1000 < user.passwordChangedAt.getTime()) {
|
|
180
|
+
throw new Error('Token expired.');
|
|
181
|
+
}
|
|
182
|
+
const payload = await this.buildTokenPayload(user._id.toString());
|
|
183
|
+
const accessToken = this.signAccessToken(payload);
|
|
184
|
+
const newRefreshToken = this.signRefreshToken({ sub: user._id.toString(), purpose: 'refresh' });
|
|
185
|
+
return { accessToken, refreshToken: newRefreshToken };
|
|
186
|
+
}
|
|
187
|
+
async forgotPassword(email) {
|
|
188
|
+
const user = await this.users.findByEmail(email);
|
|
189
|
+
if (!user)
|
|
190
|
+
return { ok: true };
|
|
191
|
+
const resetToken = this.signResetToken({ sub: user._id.toString(), purpose: 'reset' });
|
|
192
|
+
await this.mail.sendPasswordResetEmail(user.email, resetToken);
|
|
193
|
+
return { ok: true };
|
|
194
|
+
}
|
|
195
|
+
async resetPassword(token, newPassword) {
|
|
196
|
+
const decoded = jwt.verify(token, this.getEnv('JWT_RESET_SECRET'));
|
|
197
|
+
if (decoded.purpose !== 'reset')
|
|
198
|
+
throw new Error('Invalid token purpose.');
|
|
199
|
+
const user = await this.users.findById(decoded.sub);
|
|
200
|
+
if (!user)
|
|
201
|
+
throw new Error('User not found.');
|
|
202
|
+
const salt = await bcryptjs_1.default.genSalt(10);
|
|
203
|
+
user.password = await bcryptjs_1.default.hash(newPassword, salt);
|
|
204
|
+
user.passwordChangedAt = new Date();
|
|
205
|
+
await user.save();
|
|
206
|
+
return { ok: true };
|
|
207
|
+
}
|
|
208
|
+
async deleteAccount(userId) {
|
|
209
|
+
await this.users.deleteById(userId);
|
|
210
|
+
return { ok: true };
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
exports.AuthService = AuthService;
|
|
214
|
+
exports.AuthService = AuthService = __decorate([
|
|
215
|
+
(0, common_1.Injectable)(),
|
|
216
|
+
__metadata("design:paramtypes", [user_repository_1.UserRepository,
|
|
217
|
+
mail_service_1.MailService,
|
|
218
|
+
role_repository_1.RoleRepository])
|
|
219
|
+
], AuthService);
|
|
@@ -0,0 +1,39 @@
|
|
|
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.MailService = void 0;
|
|
7
|
+
const nodemailer_1 = __importDefault(require("nodemailer"));
|
|
8
|
+
class MailService {
|
|
9
|
+
constructor() {
|
|
10
|
+
this.transporter = nodemailer_1.default.createTransport({
|
|
11
|
+
host: process.env.SMTP_HOST,
|
|
12
|
+
port: parseInt(process.env.SMTP_PORT, 10),
|
|
13
|
+
secure: process.env.SMTP_SECURE === 'true',
|
|
14
|
+
auth: {
|
|
15
|
+
user: process.env.SMTP_USER,
|
|
16
|
+
pass: process.env.SMTP_PASS
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
async sendVerificationEmail(email, token) {
|
|
21
|
+
const url = `${process.env.FRONTEND_URL}/confirm-email?token=${token}`;
|
|
22
|
+
await this.transporter.sendMail({
|
|
23
|
+
from: process.env.FROM_EMAIL,
|
|
24
|
+
to: email,
|
|
25
|
+
subject: 'Verify your email',
|
|
26
|
+
text: `Click to verify your email: ${url}`
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
async sendPasswordResetEmail(email, token) {
|
|
30
|
+
const url = `${process.env.FRONTEND_URL}/reset-password?token=${token}`;
|
|
31
|
+
await this.transporter.sendMail({
|
|
32
|
+
from: process.env.FROM_EMAIL,
|
|
33
|
+
to: email,
|
|
34
|
+
subject: 'Reset your password',
|
|
35
|
+
text: `Reset your password: ${url}`
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
exports.MailService = MailService;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { UserRepository } from '../repositories/user.repository';
|
|
2
|
+
import { RoleRepository } from '../repositories/role.repository';
|
|
3
|
+
import { AuthService } from './auth.service';
|
|
4
|
+
export declare class OAuthService {
|
|
5
|
+
private readonly users;
|
|
6
|
+
private readonly roles;
|
|
7
|
+
private readonly auth;
|
|
8
|
+
private msJwks;
|
|
9
|
+
constructor(users: UserRepository, roles: RoleRepository, auth: AuthService);
|
|
10
|
+
private getDefaultRoleId;
|
|
11
|
+
private verifyMicrosoftIdToken;
|
|
12
|
+
loginWithMicrosoft(idToken: string): Promise<{
|
|
13
|
+
accessToken: string;
|
|
14
|
+
refreshToken: string;
|
|
15
|
+
}>;
|
|
16
|
+
loginWithGoogleIdToken(idToken: string): Promise<{
|
|
17
|
+
accessToken: string;
|
|
18
|
+
refreshToken: string;
|
|
19
|
+
}>;
|
|
20
|
+
loginWithGoogleCode(code: string): Promise<{
|
|
21
|
+
accessToken: string;
|
|
22
|
+
refreshToken: string;
|
|
23
|
+
}>;
|
|
24
|
+
loginWithFacebook(accessToken: string): Promise<{
|
|
25
|
+
accessToken: string;
|
|
26
|
+
refreshToken: string;
|
|
27
|
+
}>;
|
|
28
|
+
findOrCreateOAuthUser(email: string, name?: string): Promise<{
|
|
29
|
+
accessToken: string;
|
|
30
|
+
refreshToken: string;
|
|
31
|
+
}>;
|
|
32
|
+
}
|
|
@@ -0,0 +1,138 @@
|
|
|
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 __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.OAuthService = void 0;
|
|
16
|
+
const common_1 = require("@nestjs/common");
|
|
17
|
+
const axios_1 = __importDefault(require("axios"));
|
|
18
|
+
const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
|
|
19
|
+
const jwks_rsa_1 = __importDefault(require("jwks-rsa"));
|
|
20
|
+
const user_repository_1 = require("../repositories/user.repository");
|
|
21
|
+
const role_repository_1 = require("../repositories/role.repository");
|
|
22
|
+
const auth_service_1 = require("./auth.service");
|
|
23
|
+
let OAuthService = class OAuthService {
|
|
24
|
+
constructor(users, roles, auth) {
|
|
25
|
+
this.users = users;
|
|
26
|
+
this.roles = roles;
|
|
27
|
+
this.auth = auth;
|
|
28
|
+
this.msJwks = (0, jwks_rsa_1.default)({
|
|
29
|
+
jwksUri: 'https://login.microsoftonline.com/common/discovery/v2.0/keys',
|
|
30
|
+
cache: true,
|
|
31
|
+
rateLimit: true,
|
|
32
|
+
jwksRequestsPerMinute: 5,
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
async getDefaultRoleId() {
|
|
36
|
+
const role = await this.roles.findByName('user');
|
|
37
|
+
if (!role)
|
|
38
|
+
throw new Error('Default role not seeded.');
|
|
39
|
+
return role._id;
|
|
40
|
+
}
|
|
41
|
+
verifyMicrosoftIdToken(idToken) {
|
|
42
|
+
return new Promise((resolve, reject) => {
|
|
43
|
+
const getKey = (header, cb) => {
|
|
44
|
+
this.msJwks
|
|
45
|
+
.getSigningKey(header.kid)
|
|
46
|
+
.then((k) => cb(null, k.getPublicKey()))
|
|
47
|
+
.catch(cb);
|
|
48
|
+
};
|
|
49
|
+
jsonwebtoken_1.default.verify(idToken, getKey, { algorithms: ['RS256'], audience: process.env.MICROSOFT_CLIENT_ID }, (err, payload) => (err ? reject(err) : resolve(payload)));
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
async loginWithMicrosoft(idToken) {
|
|
53
|
+
const ms = await this.verifyMicrosoftIdToken(idToken);
|
|
54
|
+
const email = ms.preferred_username || ms.email;
|
|
55
|
+
if (!email)
|
|
56
|
+
throw new Error('Email missing');
|
|
57
|
+
return this.findOrCreateOAuthUser(email, ms.name);
|
|
58
|
+
}
|
|
59
|
+
async loginWithGoogleIdToken(idToken) {
|
|
60
|
+
var _a, _b;
|
|
61
|
+
const verifyResp = await axios_1.default.get('https://oauth2.googleapis.com/tokeninfo', {
|
|
62
|
+
params: { id_token: idToken },
|
|
63
|
+
});
|
|
64
|
+
const email = (_a = verifyResp.data) === null || _a === void 0 ? void 0 : _a.email;
|
|
65
|
+
if (!email)
|
|
66
|
+
throw new Error('Email missing');
|
|
67
|
+
return this.findOrCreateOAuthUser(email, (_b = verifyResp.data) === null || _b === void 0 ? void 0 : _b.name);
|
|
68
|
+
}
|
|
69
|
+
async loginWithGoogleCode(code) {
|
|
70
|
+
var _a, _b;
|
|
71
|
+
const tokenResp = await axios_1.default.post('https://oauth2.googleapis.com/token', {
|
|
72
|
+
code,
|
|
73
|
+
client_id: process.env.GOOGLE_CLIENT_ID,
|
|
74
|
+
client_secret: process.env.GOOGLE_CLIENT_SECRET,
|
|
75
|
+
redirect_uri: 'postmessage',
|
|
76
|
+
grant_type: 'authorization_code',
|
|
77
|
+
});
|
|
78
|
+
const { access_token } = tokenResp.data || {};
|
|
79
|
+
if (!access_token)
|
|
80
|
+
throw new Error('Failed to exchange code');
|
|
81
|
+
const profileResp = await axios_1.default.get('https://www.googleapis.com/oauth2/v2/userinfo', {
|
|
82
|
+
headers: { Authorization: `Bearer ${access_token}` },
|
|
83
|
+
});
|
|
84
|
+
const email = (_a = profileResp.data) === null || _a === void 0 ? void 0 : _a.email;
|
|
85
|
+
if (!email)
|
|
86
|
+
throw new Error('Email missing');
|
|
87
|
+
return this.findOrCreateOAuthUser(email, (_b = profileResp.data) === null || _b === void 0 ? void 0 : _b.name);
|
|
88
|
+
}
|
|
89
|
+
async loginWithFacebook(accessToken) {
|
|
90
|
+
var _a, _b, _c, _d, _e;
|
|
91
|
+
const appTokenResp = await axios_1.default.get('https://graph.facebook.com/oauth/access_token', {
|
|
92
|
+
params: {
|
|
93
|
+
client_id: process.env.FB_CLIENT_ID,
|
|
94
|
+
client_secret: process.env.FB_CLIENT_SECRET,
|
|
95
|
+
grant_type: 'client_credentials',
|
|
96
|
+
},
|
|
97
|
+
});
|
|
98
|
+
const appAccessToken = (_a = appTokenResp.data) === null || _a === void 0 ? void 0 : _a.access_token;
|
|
99
|
+
const debug = await axios_1.default.get('https://graph.facebook.com/debug_token', {
|
|
100
|
+
params: { input_token: accessToken, access_token: appAccessToken },
|
|
101
|
+
});
|
|
102
|
+
if (!((_c = (_b = debug.data) === null || _b === void 0 ? void 0 : _b.data) === null || _c === void 0 ? void 0 : _c.is_valid))
|
|
103
|
+
throw new Error('Invalid Facebook token');
|
|
104
|
+
const me = await axios_1.default.get('https://graph.facebook.com/me', {
|
|
105
|
+
params: { access_token: accessToken, fields: 'id,name,email' },
|
|
106
|
+
});
|
|
107
|
+
const email = (_d = me.data) === null || _d === void 0 ? void 0 : _d.email;
|
|
108
|
+
if (!email)
|
|
109
|
+
throw new Error('Email missing');
|
|
110
|
+
return this.findOrCreateOAuthUser(email, (_e = me.data) === null || _e === void 0 ? void 0 : _e.name);
|
|
111
|
+
}
|
|
112
|
+
async findOrCreateOAuthUser(email, name) {
|
|
113
|
+
let user = await this.users.findByEmail(email);
|
|
114
|
+
if (!user) {
|
|
115
|
+
const [fname, ...rest] = (name || 'User OAuth').split(' ');
|
|
116
|
+
const lname = rest.join(' ') || 'OAuth';
|
|
117
|
+
const defaultRoleId = await this.getDefaultRoleId();
|
|
118
|
+
user = await this.users.create({
|
|
119
|
+
fullname: { fname, lname },
|
|
120
|
+
username: email.split('@')[0],
|
|
121
|
+
email,
|
|
122
|
+
roles: [defaultRoleId],
|
|
123
|
+
isVerified: true,
|
|
124
|
+
isBanned: false,
|
|
125
|
+
passwordChangedAt: new Date()
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
const { accessToken, refreshToken } = await this.auth.issueTokensForUser(user._id.toString());
|
|
129
|
+
return { accessToken, refreshToken };
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
exports.OAuthService = OAuthService;
|
|
133
|
+
exports.OAuthService = OAuthService = __decorate([
|
|
134
|
+
(0, common_1.Injectable)(),
|
|
135
|
+
__metadata("design:paramtypes", [user_repository_1.UserRepository,
|
|
136
|
+
role_repository_1.RoleRepository,
|
|
137
|
+
auth_service_1.AuthService])
|
|
138
|
+
], OAuthService);
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { PermissionRepository } from '../repositories/permission.repository';
|
|
2
|
+
import { CreatePermissionDto } from '../dtos/permission/create-permission.dto';
|
|
3
|
+
import { UpdatePermissionDto } from '../dtos/permission/update-permission.dto';
|
|
4
|
+
export declare class PermissionsService {
|
|
5
|
+
private readonly perms;
|
|
6
|
+
constructor(perms: PermissionRepository);
|
|
7
|
+
create(dto: CreatePermissionDto): Promise<import("mongoose").Document<unknown, {}, import("../models/permission.model").PermissionDocument> & import("../models/permission.model").Permission & import("mongoose").Document<any, any, any> & {
|
|
8
|
+
_id: import("mongoose").Types.ObjectId;
|
|
9
|
+
}>;
|
|
10
|
+
list(): Promise<(import("mongoose").FlattenMaps<import("../models/permission.model").PermissionDocument> & {
|
|
11
|
+
_id: import("mongoose").Types.ObjectId;
|
|
12
|
+
})[]>;
|
|
13
|
+
update(id: string, dto: UpdatePermissionDto): Promise<import("mongoose").Document<unknown, {}, import("../models/permission.model").PermissionDocument> & import("../models/permission.model").Permission & import("mongoose").Document<any, any, any> & {
|
|
14
|
+
_id: import("mongoose").Types.ObjectId;
|
|
15
|
+
}>;
|
|
16
|
+
delete(id: string): Promise<{
|
|
17
|
+
ok: boolean;
|
|
18
|
+
}>;
|
|
19
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
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
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.PermissionsService = void 0;
|
|
13
|
+
const common_1 = require("@nestjs/common");
|
|
14
|
+
const permission_repository_1 = require("../repositories/permission.repository");
|
|
15
|
+
let PermissionsService = class PermissionsService {
|
|
16
|
+
constructor(perms) {
|
|
17
|
+
this.perms = perms;
|
|
18
|
+
}
|
|
19
|
+
async create(dto) {
|
|
20
|
+
if (await this.perms.findByName(dto.name))
|
|
21
|
+
throw new Error('Permission already exists.');
|
|
22
|
+
return this.perms.create(dto);
|
|
23
|
+
}
|
|
24
|
+
async list() {
|
|
25
|
+
return this.perms.list();
|
|
26
|
+
}
|
|
27
|
+
async update(id, dto) {
|
|
28
|
+
const perm = await this.perms.updateById(id, dto);
|
|
29
|
+
if (!perm)
|
|
30
|
+
throw new Error('Permission not found.');
|
|
31
|
+
return perm;
|
|
32
|
+
}
|
|
33
|
+
async delete(id) {
|
|
34
|
+
const perm = await this.perms.deleteById(id);
|
|
35
|
+
if (!perm)
|
|
36
|
+
throw new Error('Permission not found.');
|
|
37
|
+
return { ok: true };
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
exports.PermissionsService = PermissionsService;
|
|
41
|
+
exports.PermissionsService = PermissionsService = __decorate([
|
|
42
|
+
(0, common_1.Injectable)(),
|
|
43
|
+
__metadata("design:paramtypes", [permission_repository_1.PermissionRepository])
|
|
44
|
+
], PermissionsService);
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { RoleRepository } from '../repositories/role.repository';
|
|
2
|
+
import { CreateRoleDto } from '../dtos/role/create-role.dto';
|
|
3
|
+
import { UpdateRoleDto } from '../dtos/role/update-role.dto';
|
|
4
|
+
import { Types } from 'mongoose';
|
|
5
|
+
export declare class RolesService {
|
|
6
|
+
private readonly roles;
|
|
7
|
+
constructor(roles: RoleRepository);
|
|
8
|
+
create(dto: CreateRoleDto): Promise<import("mongoose").Document<unknown, {}, import("../models/role.model").RoleDocument> & import("../models/role.model").Role & import("mongoose").Document<any, any, any> & {
|
|
9
|
+
_id: Types.ObjectId;
|
|
10
|
+
}>;
|
|
11
|
+
list(): Promise<(import("mongoose").FlattenMaps<import("../models/role.model").RoleDocument> & {
|
|
12
|
+
_id: Types.ObjectId;
|
|
13
|
+
})[]>;
|
|
14
|
+
update(id: string, dto: UpdateRoleDto): Promise<import("mongoose").Document<unknown, {}, import("../models/role.model").RoleDocument> & import("../models/role.model").Role & import("mongoose").Document<any, any, any> & {
|
|
15
|
+
_id: Types.ObjectId;
|
|
16
|
+
}>;
|
|
17
|
+
delete(id: string): Promise<{
|
|
18
|
+
ok: boolean;
|
|
19
|
+
}>;
|
|
20
|
+
setPermissions(roleId: string, permissionIds: string[]): Promise<import("mongoose").Document<unknown, {}, import("../models/role.model").RoleDocument> & import("../models/role.model").Role & import("mongoose").Document<any, any, any> & {
|
|
21
|
+
_id: Types.ObjectId;
|
|
22
|
+
}>;
|
|
23
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
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
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.RolesService = void 0;
|
|
13
|
+
const common_1 = require("@nestjs/common");
|
|
14
|
+
const role_repository_1 = require("../repositories/role.repository");
|
|
15
|
+
const mongoose_1 = require("mongoose");
|
|
16
|
+
let RolesService = class RolesService {
|
|
17
|
+
constructor(roles) {
|
|
18
|
+
this.roles = roles;
|
|
19
|
+
}
|
|
20
|
+
async create(dto) {
|
|
21
|
+
if (await this.roles.findByName(dto.name))
|
|
22
|
+
throw new Error('Role already exists.');
|
|
23
|
+
const permIds = (dto.permissions || []).map((p) => new mongoose_1.Types.ObjectId(p));
|
|
24
|
+
return this.roles.create({ name: dto.name, permissions: permIds });
|
|
25
|
+
}
|
|
26
|
+
async list() {
|
|
27
|
+
return this.roles.list();
|
|
28
|
+
}
|
|
29
|
+
async update(id, dto) {
|
|
30
|
+
const data = { ...dto };
|
|
31
|
+
if (dto.permissions) {
|
|
32
|
+
data.permissions = dto.permissions.map((p) => new mongoose_1.Types.ObjectId(p));
|
|
33
|
+
}
|
|
34
|
+
const role = await this.roles.updateById(id, data);
|
|
35
|
+
if (!role)
|
|
36
|
+
throw new Error('Role not found.');
|
|
37
|
+
return role;
|
|
38
|
+
}
|
|
39
|
+
async delete(id) {
|
|
40
|
+
const role = await this.roles.deleteById(id);
|
|
41
|
+
if (!role)
|
|
42
|
+
throw new Error('Role not found.');
|
|
43
|
+
return { ok: true };
|
|
44
|
+
}
|
|
45
|
+
async setPermissions(roleId, permissionIds) {
|
|
46
|
+
const permIds = permissionIds.map((p) => new mongoose_1.Types.ObjectId(p));
|
|
47
|
+
const role = await this.roles.updateById(roleId, { permissions: permIds });
|
|
48
|
+
if (!role)
|
|
49
|
+
throw new Error('Role not found.');
|
|
50
|
+
return role;
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
exports.RolesService = RolesService;
|
|
54
|
+
exports.RolesService = RolesService = __decorate([
|
|
55
|
+
(0, common_1.Injectable)(),
|
|
56
|
+
__metadata("design:paramtypes", [role_repository_1.RoleRepository])
|
|
57
|
+
], RolesService);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { RoleRepository } from '../repositories/role.repository';
|
|
2
|
+
import { PermissionRepository } from '../repositories/permission.repository';
|
|
3
|
+
export declare class SeedService {
|
|
4
|
+
private readonly roles;
|
|
5
|
+
private readonly perms;
|
|
6
|
+
constructor(roles: RoleRepository, perms: PermissionRepository);
|
|
7
|
+
seedDefaults(): Promise<{
|
|
8
|
+
adminRoleId: any;
|
|
9
|
+
userRoleId: any;
|
|
10
|
+
}>;
|
|
11
|
+
}
|
|
@@ -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 __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.SeedService = void 0;
|
|
13
|
+
const common_1 = require("@nestjs/common");
|
|
14
|
+
const role_repository_1 = require("../repositories/role.repository");
|
|
15
|
+
const permission_repository_1 = require("../repositories/permission.repository");
|
|
16
|
+
const mongoose_1 = require("mongoose");
|
|
17
|
+
let SeedService = class SeedService {
|
|
18
|
+
constructor(roles, perms) {
|
|
19
|
+
this.roles = roles;
|
|
20
|
+
this.perms = perms;
|
|
21
|
+
}
|
|
22
|
+
async seedDefaults() {
|
|
23
|
+
const permNames = ['users:manage', 'roles:manage', 'permissions:manage'];
|
|
24
|
+
const permIds = [];
|
|
25
|
+
for (const name of permNames) {
|
|
26
|
+
let p = await this.perms.findByName(name);
|
|
27
|
+
if (!p)
|
|
28
|
+
p = await this.perms.create({ name });
|
|
29
|
+
permIds.push(p._id.toString());
|
|
30
|
+
}
|
|
31
|
+
let admin = await this.roles.findByName('admin');
|
|
32
|
+
const permissions = permIds.map((p) => new mongoose_1.Types.ObjectId(p));
|
|
33
|
+
if (!admin)
|
|
34
|
+
admin = await this.roles.create({ name: 'admin', permissions: permissions });
|
|
35
|
+
let user = await this.roles.findByName('user');
|
|
36
|
+
if (!user)
|
|
37
|
+
user = await this.roles.create({ name: 'user', permissions: [] });
|
|
38
|
+
console.log('[AuthKit] Seeded roles:', { adminRoleId: admin._id.toString(), userRoleId: user._id.toString() });
|
|
39
|
+
return {
|
|
40
|
+
adminRoleId: admin._id.toString(),
|
|
41
|
+
userRoleId: user._id.toString()
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
exports.SeedService = SeedService;
|
|
46
|
+
exports.SeedService = SeedService = __decorate([
|
|
47
|
+
(0, common_1.Injectable)(),
|
|
48
|
+
__metadata("design:paramtypes", [role_repository_1.RoleRepository,
|
|
49
|
+
permission_repository_1.PermissionRepository])
|
|
50
|
+
], SeedService);
|