najm-auth 1.1.17 → 1.1.20
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 +7 -5
- package/dist/index.d.ts +23 -5
- package/dist/index.js +38 -16
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -198,11 +198,13 @@ class PostController {
|
|
|
198
198
|
```typescript
|
|
199
199
|
import { defineRoles } from 'najm-auth';
|
|
200
200
|
|
|
201
|
-
const roles = defineRoles({
|
|
202
|
-
ADMIN: 'admin',
|
|
203
|
-
MODERATOR: 'moderator',
|
|
204
|
-
USER: 'user',
|
|
205
|
-
}
|
|
201
|
+
const roles = defineRoles({
|
|
202
|
+
ADMIN: 'admin',
|
|
203
|
+
MODERATOR: 'moderator',
|
|
204
|
+
USER: 'user',
|
|
205
|
+
}, {
|
|
206
|
+
superRoles: ['ADMIN'], // admin also passes moderator/user role guards
|
|
207
|
+
});
|
|
206
208
|
|
|
207
209
|
export const { isAdmin, isModerator, isUser } = roles;
|
|
208
210
|
|
package/dist/index.d.ts
CHANGED
|
@@ -683,8 +683,10 @@ declare class TokenService {
|
|
|
683
683
|
validateRefreshSession(refreshToken: string): Promise<string>;
|
|
684
684
|
/**
|
|
685
685
|
* Read the refresh cookie and return the userId it belongs to.
|
|
686
|
-
*
|
|
687
|
-
*
|
|
686
|
+
* Lightweight check: verifies JWT signature and ensures the user
|
|
687
|
+
* has an active session in the DB. Does NOT compare token hashes,
|
|
688
|
+
* so it is safe to call concurrently with token rotation.
|
|
689
|
+
* Throws if the cookie is missing, invalid, or the session was revoked.
|
|
688
690
|
*/
|
|
689
691
|
resolveUserFromCookie(): Promise<string>;
|
|
690
692
|
getUser(auth: string): Promise<any>;
|
|
@@ -860,6 +862,13 @@ declare class AuthService {
|
|
|
860
862
|
getUserFromCookie(): Promise<SanitizedUser & {
|
|
861
863
|
language: string;
|
|
862
864
|
}>;
|
|
865
|
+
/**
|
|
866
|
+
* Get current user — prefer access token (no cookie rotation risk),
|
|
867
|
+
* fall back to cookie when no Authorization header is present.
|
|
868
|
+
*/
|
|
869
|
+
getMe(authorization?: string): Promise<SanitizedUser & {
|
|
870
|
+
language: string;
|
|
871
|
+
}>;
|
|
863
872
|
forgotPassword(email: string): Promise<{
|
|
864
873
|
message: string;
|
|
865
874
|
}>;
|
|
@@ -887,7 +896,7 @@ declare class AuthController {
|
|
|
887
896
|
changePassword(userId: string, body: ChangePasswordDto): Promise<{
|
|
888
897
|
message: string;
|
|
889
898
|
}>;
|
|
890
|
-
userProfile(): Promise<Omit<{
|
|
899
|
+
userProfile(authorization?: string): Promise<Omit<{
|
|
891
900
|
id: string;
|
|
892
901
|
name: string;
|
|
893
902
|
createdAt: string;
|
|
@@ -982,6 +991,13 @@ type RoleInput = string | string[];
|
|
|
982
991
|
type IsGuards<T extends Record<string, string>> = {
|
|
983
992
|
[K in keyof T as `is${Capitalize<Lowercase<string & K>>}`]: () => ClassDecorator & MethodDecorator;
|
|
984
993
|
};
|
|
994
|
+
interface DefineRolesOptions<T extends Record<string, string>> {
|
|
995
|
+
/**
|
|
996
|
+
* Role keys that should implicitly pass every generated role guard, group guard,
|
|
997
|
+
* and service-layer role check created by defineRoles.
|
|
998
|
+
*/
|
|
999
|
+
superRoles?: Array<keyof T>;
|
|
1000
|
+
}
|
|
985
1001
|
interface DefineRolesResult<T extends Record<string, string>> {
|
|
986
1002
|
/** The original roles record */
|
|
987
1003
|
ROLES: T;
|
|
@@ -1001,6 +1017,8 @@ interface DefineRolesResult<T extends Record<string, string>> {
|
|
|
1001
1017
|
* ADMIN: 'admin',
|
|
1002
1018
|
* TEACHER: 'teacher',
|
|
1003
1019
|
* STUDENT: 'student',
|
|
1020
|
+
* }, {
|
|
1021
|
+
* superRoles: ['ADMIN'],
|
|
1004
1022
|
* });
|
|
1005
1023
|
*
|
|
1006
1024
|
* // HTTP guards
|
|
@@ -1010,7 +1028,7 @@ interface DefineRolesResult<T extends Record<string, string>> {
|
|
|
1010
1028
|
* if (hasRole(user.role, 'ADMIN', 'TEACHER')) { ... }
|
|
1011
1029
|
* ```
|
|
1012
1030
|
*/
|
|
1013
|
-
declare function defineRoles<T extends Record<string, string>>(roles: T): DefineRolesResult<T> & IsGuards<T>;
|
|
1031
|
+
declare function defineRoles<T extends Record<string, string>>(roles: T, options?: DefineRolesOptions<T>): DefineRolesResult<T> & IsGuards<T>;
|
|
1014
1032
|
|
|
1015
1033
|
declare class RoleGuard {
|
|
1016
1034
|
canActivate(allowedRoles: RoleInput, userRole: string): false | {
|
|
@@ -1818,4 +1836,4 @@ declare const authSeed: (config: AuthSeedConfig) => Record<string, SeedEntry>;
|
|
|
1818
1836
|
*/
|
|
1819
1837
|
declare function seedAuthData(config: SeedAuthDataConfig): Promise<SeedAuthDataResult>;
|
|
1820
1838
|
|
|
1821
|
-
export { AUTH_CONFIG, en as AUTH_EN, AUTH_LOCALES, AUTH_MODULE, AUTH_PERMISSIONS, AUTH_ROLE, AUTH_SCHEMA, AUTH_SUPPORTED_LANGUAGES, AUTH_USER, type AssignPermissionDto, type AssignRoleDto, type AssignRoleParams, type AuthConfig, AuthController, AuthGuard, type AuthPluginConfig, AuthQueries, AuthResolver, type AuthSchema, type AuthSeedConfig, AuthService, type AuthUser, Can, CanCreate, CanDelete, CanList, CanRead, CanUpdate, type ChainableGuard, type ChangePasswordDto, type CheckPermissionDto, type ConfiguredOwnership, type ConfirmResetPasswordDto, CookieManager, type CreatePermissionDto, type CreateRoleDto, type CreateTokenDto, type CreateUserDto, type EmailParam, EncryptionService, type JwtConfig, type JwtPayload, type LanguageParam, type LoginDto, NewPermission, NewRoleEntity, NewUser, Owned, type OwnedMethods, type OwnershipConfig, type OwnershipProvider, type OwnershipRule, OwnershipToken, type OwnershipTokenOptions, Permission, PermissionController, PermissionGuard, type PermissionIdParam, PermissionRepository, PermissionService, PermissionValidator, Policy, ROLES, ROLE_GROUPS, type RefreshTokenDto, type ResetPasswordDto, type ResourceAccessor, type ResourceGuards, type ResourceGuardsOptions, type RevokeTokenDto, Role, RoleController, RoleEntity, RoleGuard, type RoleIdParam, type RoleInput, RolePermission, RoleRepository, RoleService, type RoleType, RoleValidator, type SanitizedUser, ScopeContext, type ScopeResult, type SeedAuthDataConfig, type SeedAuthDataResult, type SeedUserConfig, TOKEN_STATUS, TOKEN_TYPE, type TokenIdParam, type TokenPair, TokenRepository, TokenService, USER_STATUS, type UpdatePermissionDto, type UpdateRoleDto, type UpdateTokenDto, type UpdateUserDto, User, UserController, type UserIdInParam, type UserIdParam, UserRepository, UserService, UserValidator, type UserWithPermissions, type VerifyTokenDto, assignPermissionDto, assignRoleDto, assignRoleParams, auth$1 as auth, authSeed, avatarsPath, calculateAge, calculateYearsOfExperience, changePasswordDto, checkPermissionDto, clean, configureOwnership, confirmResetPasswordDto, createPermissionDto, createRoleDto, createTokenDto, createUserDto, defineRoles, emailParam, formatDate, getAuthLocale, getAvatarFile, isAdmin, isAdministrator, isAuth, isEmpty, isFile, isPath, join, languageParam, loginDto, own, parseSchema, permissionIdParam, pickProps, refreshTokenDto, resetPasswordDto, revokeTokenDto, roleIdParam, seedAuthData, setConfiguredCookieName, tokenIdParam, updatePermissionDto, updateRoleDto, updateTokenDto, updateUserDto, userIdInParam, userIdParam, verifyTokenDto, where };
|
|
1839
|
+
export { AUTH_CONFIG, en as AUTH_EN, AUTH_LOCALES, AUTH_MODULE, AUTH_PERMISSIONS, AUTH_ROLE, AUTH_SCHEMA, AUTH_SUPPORTED_LANGUAGES, AUTH_USER, type AssignPermissionDto, type AssignRoleDto, type AssignRoleParams, type AuthConfig, AuthController, AuthGuard, type AuthPluginConfig, AuthQueries, AuthResolver, type AuthSchema, type AuthSeedConfig, AuthService, type AuthUser, Can, CanCreate, CanDelete, CanList, CanRead, CanUpdate, type ChainableGuard, type ChangePasswordDto, type CheckPermissionDto, type ConfiguredOwnership, type ConfirmResetPasswordDto, CookieManager, type CreatePermissionDto, type CreateRoleDto, type CreateTokenDto, type CreateUserDto, type DefineRolesOptions, type EmailParam, EncryptionService, type JwtConfig, type JwtPayload, type LanguageParam, type LoginDto, NewPermission, NewRoleEntity, NewUser, Owned, type OwnedMethods, type OwnershipConfig, type OwnershipProvider, type OwnershipRule, OwnershipToken, type OwnershipTokenOptions, Permission, PermissionController, PermissionGuard, type PermissionIdParam, PermissionRepository, PermissionService, PermissionValidator, Policy, ROLES, ROLE_GROUPS, type RefreshTokenDto, type ResetPasswordDto, type ResourceAccessor, type ResourceGuards, type ResourceGuardsOptions, type RevokeTokenDto, Role, RoleController, RoleEntity, RoleGuard, type RoleIdParam, type RoleInput, RolePermission, RoleRepository, RoleService, type RoleType, RoleValidator, type SanitizedUser, ScopeContext, type ScopeResult, type SeedAuthDataConfig, type SeedAuthDataResult, type SeedUserConfig, TOKEN_STATUS, TOKEN_TYPE, type TokenIdParam, type TokenPair, TokenRepository, TokenService, USER_STATUS, type UpdatePermissionDto, type UpdateRoleDto, type UpdateTokenDto, type UpdateUserDto, User, UserController, type UserIdInParam, type UserIdParam, UserRepository, UserService, UserValidator, type UserWithPermissions, type VerifyTokenDto, assignPermissionDto, assignRoleDto, assignRoleParams, auth$1 as auth, authSeed, avatarsPath, calculateAge, calculateYearsOfExperience, changePasswordDto, checkPermissionDto, clean, configureOwnership, confirmResetPasswordDto, createPermissionDto, createRoleDto, createTokenDto, createUserDto, defineRoles, emailParam, formatDate, getAuthLocale, getAvatarFile, isAdmin, isAdministrator, isAuth, isEmpty, isFile, isPath, join, languageParam, loginDto, own, parseSchema, permissionIdParam, pickProps, refreshTokenDto, resetPasswordDto, revokeTokenDto, roleIdParam, seedAuthData, setConfiguredCookieName, tokenIdParam, updatePermissionDto, updateRoleDto, updateTokenDto, updateUserDto, userIdInParam, userIdParam, verifyTokenDto, where };
|
package/dist/index.js
CHANGED
|
@@ -1408,24 +1408,28 @@ var TokenService = class TokenService2 {
|
|
|
1408
1408
|
}
|
|
1409
1409
|
const isValid = this.hashToken(refreshToken) === stored.token;
|
|
1410
1410
|
if (!isValid) {
|
|
1411
|
-
if (stored.tokenFamily) {
|
|
1412
|
-
await this.tokenRepository.revokeByFamily(stored.tokenFamily);
|
|
1413
|
-
}
|
|
1414
1411
|
Err5(this.t("errors.refreshTokenInvalid"));
|
|
1415
1412
|
}
|
|
1416
1413
|
return userId;
|
|
1417
1414
|
}
|
|
1418
1415
|
/**
|
|
1419
1416
|
* Read the refresh cookie and return the userId it belongs to.
|
|
1420
|
-
*
|
|
1421
|
-
*
|
|
1417
|
+
* Lightweight check: verifies JWT signature and ensures the user
|
|
1418
|
+
* has an active session in the DB. Does NOT compare token hashes,
|
|
1419
|
+
* so it is safe to call concurrently with token rotation.
|
|
1420
|
+
* Throws if the cookie is missing, invalid, or the session was revoked.
|
|
1422
1421
|
*/
|
|
1423
1422
|
async resolveUserFromCookie() {
|
|
1424
1423
|
const refreshToken = this.cookieManager.getRefreshToken();
|
|
1425
1424
|
if (!refreshToken) {
|
|
1426
1425
|
Err5(this.t("errors.refreshTokenMissing"));
|
|
1427
1426
|
}
|
|
1428
|
-
|
|
1427
|
+
const userId = this.verifyRefreshToken(refreshToken);
|
|
1428
|
+
const stored = await this.tokenRepository.getRefreshTokenWithFamily(userId);
|
|
1429
|
+
if (!stored) {
|
|
1430
|
+
Err5(this.t("errors.refreshTokenInvalid"));
|
|
1431
|
+
}
|
|
1432
|
+
return userId;
|
|
1429
1433
|
}
|
|
1430
1434
|
// ============ USER RETRIEVAL (MAIN METHOD) ============
|
|
1431
1435
|
async getUser(auth2) {
|
|
@@ -1552,9 +1556,6 @@ var TokenService = class TokenService2 {
|
|
|
1552
1556
|
}
|
|
1553
1557
|
const isValid = this.hashToken(refreshToken) === stored.token;
|
|
1554
1558
|
if (!isValid) {
|
|
1555
|
-
if (stored.tokenFamily) {
|
|
1556
|
-
await this.tokenRepository.revokeByFamily(stored.tokenFamily);
|
|
1557
|
-
}
|
|
1558
1559
|
Err5(this.t("errors.refreshTokenInvalid"));
|
|
1559
1560
|
}
|
|
1560
1561
|
return this.generateTokens(userId, stored.tokenFamily ?? void 0);
|
|
@@ -1758,6 +1759,20 @@ var AuthService = class AuthService2 {
|
|
|
1758
1759
|
const lang = this.i18nService.getCurrentLanguage();
|
|
1759
1760
|
return { ...user, language: lang };
|
|
1760
1761
|
}
|
|
1762
|
+
/**
|
|
1763
|
+
* Get current user — prefer access token (no cookie rotation risk),
|
|
1764
|
+
* fall back to cookie when no Authorization header is present.
|
|
1765
|
+
*/
|
|
1766
|
+
async getMe(authorization) {
|
|
1767
|
+
if (authorization) {
|
|
1768
|
+
const user = await this.tokenService.getUser(authorization);
|
|
1769
|
+
if (user) {
|
|
1770
|
+
const lang = this.i18nService.getCurrentLanguage();
|
|
1771
|
+
return { ...user, language: lang };
|
|
1772
|
+
}
|
|
1773
|
+
}
|
|
1774
|
+
return this.getUserFromCookie();
|
|
1775
|
+
}
|
|
1761
1776
|
async forgotPassword(email2) {
|
|
1762
1777
|
const user = await this.userService.findByEmail(email2);
|
|
1763
1778
|
if (user) {
|
|
@@ -1966,8 +1981,8 @@ var AuthController = class AuthController2 {
|
|
|
1966
1981
|
async changePassword(userId, body) {
|
|
1967
1982
|
return this.authService.changePassword(userId, body.currentPassword, body.newPassword);
|
|
1968
1983
|
}
|
|
1969
|
-
async userProfile() {
|
|
1970
|
-
return this.authService.
|
|
1984
|
+
async userProfile(authorization) {
|
|
1985
|
+
return this.authService.getMe(authorization);
|
|
1971
1986
|
}
|
|
1972
1987
|
async forgotPassword(body) {
|
|
1973
1988
|
return this.authService.forgotPassword(body.email);
|
|
@@ -2029,8 +2044,9 @@ __decorate13([
|
|
|
2029
2044
|
Get("/me"),
|
|
2030
2045
|
RateLimit({ limit: 30, window: "1m", key: cookieFingerprint() }),
|
|
2031
2046
|
ResMsg("auth.users.success.retrieved"),
|
|
2047
|
+
__param3(0, Headers("authorization")),
|
|
2032
2048
|
__metadata13("design:type", Function),
|
|
2033
|
-
__metadata13("design:paramtypes", []),
|
|
2049
|
+
__metadata13("design:paramtypes", [String]),
|
|
2034
2050
|
__metadata13("design:returntype", Promise)
|
|
2035
2051
|
], AuthController.prototype, "userProfile", null);
|
|
2036
2052
|
__decorate13([
|
|
@@ -2299,15 +2315,21 @@ var isAdministrator = composeGuards(isAuth(), Role(ROLE_GROUPS.ADMINISTRATORS));
|
|
|
2299
2315
|
|
|
2300
2316
|
// src/roles/defineRoles.ts
|
|
2301
2317
|
var Role2 = createGuard3(RoleGuard);
|
|
2302
|
-
function defineRoles(roles) {
|
|
2318
|
+
function defineRoles(roles, options) {
|
|
2303
2319
|
const ROLES2 = roles;
|
|
2320
|
+
const superRoleKeys = options?.superRoles ?? [];
|
|
2321
|
+
function resolveRoleValues(keys) {
|
|
2322
|
+
return Array.from(new Set([...keys, ...superRoleKeys].map((key) => roles[key])));
|
|
2323
|
+
}
|
|
2324
|
+
__name(resolveRoleValues, "resolveRoleValues");
|
|
2304
2325
|
const guards2 = {};
|
|
2305
2326
|
for (const [key, value] of Object.entries(roles)) {
|
|
2306
2327
|
const name = `is${key.charAt(0).toUpperCase()}${key.slice(1).toLowerCase()}`;
|
|
2307
|
-
|
|
2328
|
+
const allowedValues = resolveRoleValues([key]);
|
|
2329
|
+
guards2[name] = composeGuards2(isAuth(), Role2(allowedValues.length === 1 ? value : allowedValues));
|
|
2308
2330
|
}
|
|
2309
2331
|
function createGroupGuard(keys) {
|
|
2310
|
-
const values = keys
|
|
2332
|
+
const values = resolveRoleValues(keys);
|
|
2311
2333
|
return composeGuards2(isAuth(), Role2(values));
|
|
2312
2334
|
}
|
|
2313
2335
|
__name(createGroupGuard, "createGroupGuard");
|
|
@@ -2315,7 +2337,7 @@ function defineRoles(roles) {
|
|
|
2315
2337
|
if (!userRole)
|
|
2316
2338
|
return false;
|
|
2317
2339
|
const normalized = userRole.toLowerCase();
|
|
2318
|
-
return keys.some((
|
|
2340
|
+
return resolveRoleValues(keys).some((role) => role === normalized);
|
|
2319
2341
|
}
|
|
2320
2342
|
__name(hasRole, "hasRole");
|
|
2321
2343
|
function isInGroup(userRole, keys) {
|