@plyaz/auth 1.0.1 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/commits.txt +2 -5
- package/dist/index.cjs +389 -15649
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +96 -139
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -2
- package/release_message.txt +25 -0
- package/src/adapters/clerk/clerk.adapter.ts +1 -1
- package/src/adapters/next-auth/next-auth.adapter.ts +2 -2
- package/src/client/hooks/index.ts +5 -0
- package/src/client/hooks/useAuth.ts +4 -125
- package/src/client/hooks/useConnectedAccounts.ts +1 -13
- package/src/client/hooks/usePermissions.ts +6 -10
- package/src/client/hooks/useRBAC.ts +2 -8
- package/src/client/hooks/useSession.ts +4 -7
- package/src/client/index.ts +3 -0
- package/src/client/providers/AuthProvider.tsx +4 -89
- package/src/client/store/auth.store.ts +5 -72
- package/src/client/utils/createAuthContextValues.ts +66 -0
- package/src/client/utils/handleAuthAction.ts +29 -0
- package/src/core/blacklist/token.blacklist.ts +1 -5
- package/src/db/repositories/connected-account.repository.ts +11 -11
- package/src/db/repositories/user.repository.ts +20 -18
- package/src/flows/sign-in.flow.ts +1 -38
- package/src/flows/sign-up.flow.ts +11 -56
- package/src/index.ts +1 -8
- package/src/libs/supabase.helper.ts +8 -7
- package/src/providers/base/auth-provider.interface.ts +2 -21
- package/src/rbac/dynamic-roles.ts +22 -68
- package/src/rbac/permission-checker.ts +3 -32
- package/src/rbac/role-hierarchy.ts +0 -30
- package/src/server/decorators/current-user.decorator.ts +3 -2
- package/src/server/middleware/session.middleware.ts +1 -14
- package/src/server/services/auth.service.ts +16 -16
- package/src/server/services/session.service.ts +3 -4
- package/src/server/services/token.service.ts +3 -3
- package/src/session/cookie-store.ts +18 -18
- package/src/session/enhanced-session-manager.ts +2 -49
- package/src/session/redis-store.ts +2 -50
- package/src/strategies/oauth.strategy.ts +1 -8
- package/src/tokens/refresh-token-manager.ts +1 -100
- package/src/tokens/token-validator.ts +2 -46
- package/src/common/errors/auth.errors.ts +0 -64
- package/src/common/errors/specific-auth-errors.ts +0 -197
- package/src/common/types/auth.types.ts +0 -650
- package/src/common/types/index.ts +0 -303
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { createClient } from "@supabase/supabase-js";
|
|
2
|
+
|
|
2
3
|
import type {
|
|
3
4
|
ConnectedAccount,
|
|
4
5
|
ConnectedAccountRepository as IConnectedAccountRepository,
|
|
5
6
|
CreateConnectedAccountData,
|
|
6
7
|
UpdateConnectedAccountData,
|
|
7
|
-
} from "
|
|
8
|
-
|
|
8
|
+
} from "@plyaz/types";
|
|
9
9
|
/**
|
|
10
10
|
* Repository for managing connected accounts (provider account linking)
|
|
11
11
|
*
|
|
@@ -98,7 +98,7 @@ export class ConnectedAccountRepository implements IConnectedAccountRepository {
|
|
|
98
98
|
*/
|
|
99
99
|
async findByProvider(
|
|
100
100
|
provider: string,
|
|
101
|
-
providerAccountId: string
|
|
101
|
+
providerAccountId: string
|
|
102
102
|
): Promise<ConnectedAccount | null> {
|
|
103
103
|
const { data, error } = await this.supabase
|
|
104
104
|
.from("connected_accounts")
|
|
@@ -116,7 +116,7 @@ export class ConnectedAccountRepository implements IConnectedAccountRepository {
|
|
|
116
116
|
*/
|
|
117
117
|
async findByProviderAndId(
|
|
118
118
|
provider: string,
|
|
119
|
-
providerAccountId: string
|
|
119
|
+
providerAccountId: string
|
|
120
120
|
): Promise<ConnectedAccount | null> {
|
|
121
121
|
return this.findByProvider(provider, providerAccountId);
|
|
122
122
|
}
|
|
@@ -127,7 +127,7 @@ export class ConnectedAccountRepository implements IConnectedAccountRepository {
|
|
|
127
127
|
async updateTokens(
|
|
128
128
|
accountId: string,
|
|
129
129
|
accessToken: string,
|
|
130
|
-
refreshToken?: string
|
|
130
|
+
refreshToken?: string
|
|
131
131
|
): Promise<void> {
|
|
132
132
|
const updateData = {
|
|
133
133
|
access_token_encrypted: accessToken,
|
|
@@ -158,7 +158,7 @@ export class ConnectedAccountRepository implements IConnectedAccountRepository {
|
|
|
158
158
|
*/
|
|
159
159
|
async update(
|
|
160
160
|
id: string,
|
|
161
|
-
data: UpdateConnectedAccountData
|
|
161
|
+
data: UpdateConnectedAccountData
|
|
162
162
|
): Promise<ConnectedAccount> {
|
|
163
163
|
const updateData = this.buildUpdateData(data);
|
|
164
164
|
|
|
@@ -244,7 +244,7 @@ export class ConnectedAccountRepository implements IConnectedAccountRepository {
|
|
|
244
244
|
async linkAccount(
|
|
245
245
|
userId: string,
|
|
246
246
|
provider: string,
|
|
247
|
-
providerData: ConnectedAccount
|
|
247
|
+
providerData: ConnectedAccount
|
|
248
248
|
): Promise<ConnectedAccount> {
|
|
249
249
|
const accountData = {
|
|
250
250
|
user_id: userId,
|
|
@@ -316,7 +316,7 @@ export class ConnectedAccountRepository implements IConnectedAccountRepository {
|
|
|
316
316
|
private emitAccountLinkedEvent(
|
|
317
317
|
userId: string,
|
|
318
318
|
provider: string,
|
|
319
|
-
accountId: string
|
|
319
|
+
accountId: string
|
|
320
320
|
): void {
|
|
321
321
|
// Mock event emission - in real implementation would use event system
|
|
322
322
|
globalThis.console.log("Event: auth.account.linked", {
|
|
@@ -337,7 +337,7 @@ export class ConnectedAccountRepository implements IConnectedAccountRepository {
|
|
|
337
337
|
private emitAccountUnlinkedEvent(
|
|
338
338
|
userId: string,
|
|
339
339
|
provider: string,
|
|
340
|
-
accountId: string
|
|
340
|
+
accountId: string
|
|
341
341
|
): void {
|
|
342
342
|
// Mock event emission - in real implementation would use event system
|
|
343
343
|
globalThis.console.log("Event: auth.account.unlinked", {
|
|
@@ -353,7 +353,7 @@ export class ConnectedAccountRepository implements IConnectedAccountRepository {
|
|
|
353
353
|
* @private
|
|
354
354
|
*/
|
|
355
355
|
private transformToDbFormat(
|
|
356
|
-
data: CreateConnectedAccountData
|
|
356
|
+
data: CreateConnectedAccountData
|
|
357
357
|
): Record<
|
|
358
358
|
string,
|
|
359
359
|
string | undefined | Record<string, unknown> | Date | boolean
|
|
@@ -388,7 +388,7 @@ export class ConnectedAccountRepository implements IConnectedAccountRepository {
|
|
|
388
388
|
* @private
|
|
389
389
|
*/
|
|
390
390
|
private buildUpdateData(
|
|
391
|
-
data: UpdateConnectedAccountData
|
|
391
|
+
data: UpdateConnectedAccountData
|
|
392
392
|
): Record<string, string> {
|
|
393
393
|
const result: Record<string, string> = {
|
|
394
394
|
updated_at: new Date().toString(),
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { createClient } from "@supabase/supabase-js";
|
|
2
|
+
|
|
2
3
|
import type {
|
|
3
|
-
|
|
4
|
+
AUTHPROVIDER,
|
|
5
|
+
AuthUser,
|
|
4
6
|
UserRepository as IUserRepository,
|
|
5
7
|
CreateUserData,
|
|
6
8
|
UpdateUserData,
|
|
7
|
-
|
|
8
|
-
|
|
9
|
+
UserInfo,
|
|
10
|
+
} from "@plyaz/types";
|
|
9
11
|
/**
|
|
10
12
|
* Repository for managing user accounts
|
|
11
13
|
*
|
|
@@ -35,7 +37,7 @@ export class UserRepository implements IUserRepository {
|
|
|
35
37
|
constructor(
|
|
36
38
|
supabaseUrl: string,
|
|
37
39
|
supabaseKey: string,
|
|
38
|
-
private schema: "public" | "backoffice" = "public"
|
|
40
|
+
private schema: "public" | "backoffice" = "public"
|
|
39
41
|
) {
|
|
40
42
|
this.supabase = createClient(supabaseUrl, supabaseKey);
|
|
41
43
|
}
|
|
@@ -45,7 +47,7 @@ export class UserRepository implements IUserRepository {
|
|
|
45
47
|
* @param id - User UUID
|
|
46
48
|
* @returns Promise resolving to User or null if not found
|
|
47
49
|
*/
|
|
48
|
-
async findById(id: string): Promise<
|
|
50
|
+
async findById(id: string): Promise<UserInfo | null> {
|
|
49
51
|
const { data, error } = await this.supabase
|
|
50
52
|
.from("users")
|
|
51
53
|
.select("*")
|
|
@@ -60,7 +62,7 @@ export class UserRepository implements IUserRepository {
|
|
|
60
62
|
* @param email - User email address
|
|
61
63
|
* @returns Promise resolving to User or null if not found
|
|
62
64
|
*/
|
|
63
|
-
async findByEmail(email: string): Promise<
|
|
65
|
+
async findByEmail(email: string): Promise<UserInfo | null> {
|
|
64
66
|
const { data, error } = await this.supabase
|
|
65
67
|
.from("users")
|
|
66
68
|
.select("*")
|
|
@@ -79,8 +81,8 @@ export class UserRepository implements IUserRepository {
|
|
|
79
81
|
*/
|
|
80
82
|
async findByProviderAccount(
|
|
81
83
|
provider: string,
|
|
82
|
-
providerAccountId: string
|
|
83
|
-
): Promise<
|
|
84
|
+
providerAccountId: string
|
|
85
|
+
): Promise<UserInfo | null> {
|
|
84
86
|
const { data: accountData, error: accountError } = await this.supabase
|
|
85
87
|
.from("connected_accounts")
|
|
86
88
|
.select("user_id")
|
|
@@ -97,7 +99,7 @@ export class UserRepository implements IUserRepository {
|
|
|
97
99
|
* @returns Promise resolving to created User
|
|
98
100
|
* @throws Error if creation fails
|
|
99
101
|
*/
|
|
100
|
-
async create(data: CreateUserData): Promise<
|
|
102
|
+
async create(data: CreateUserData): Promise<UserInfo> {
|
|
101
103
|
const insertData = this.transformToDbFormat(data);
|
|
102
104
|
const { data: userData, error } = await this.supabase
|
|
103
105
|
.from("users")
|
|
@@ -117,7 +119,7 @@ export class UserRepository implements IUserRepository {
|
|
|
117
119
|
* @returns Promise resolving to updated User
|
|
118
120
|
* @throws Error if update fails
|
|
119
121
|
*/
|
|
120
|
-
async update(id: string, data: UpdateUserData): Promise<
|
|
122
|
+
async update(id: string, data: UpdateUserData): Promise<UserInfo> {
|
|
121
123
|
const updateData = this.buildUpdateData(data);
|
|
122
124
|
const { data: userData, error } = await this.supabase
|
|
123
125
|
.from("users")
|
|
@@ -145,8 +147,8 @@ export class UserRepository implements IUserRepository {
|
|
|
145
147
|
*/
|
|
146
148
|
async findByCredentials(
|
|
147
149
|
email: string,
|
|
148
|
-
passwordHash: string
|
|
149
|
-
): Promise<
|
|
150
|
+
passwordHash: string
|
|
151
|
+
): Promise<UserInfo | null> {
|
|
150
152
|
const { data, error } = await this.supabase
|
|
151
153
|
.from("users")
|
|
152
154
|
.select("*")
|
|
@@ -162,7 +164,7 @@ export class UserRepository implements IUserRepository {
|
|
|
162
164
|
async assignRole(
|
|
163
165
|
userId: string,
|
|
164
166
|
role: string,
|
|
165
|
-
assignedBy?: string
|
|
167
|
+
assignedBy?: string
|
|
166
168
|
): Promise<void> {
|
|
167
169
|
const { error } = await this.supabase.from("user_roles").insert({
|
|
168
170
|
user_id: userId,
|
|
@@ -219,7 +221,7 @@ export class UserRepository implements IUserRepository {
|
|
|
219
221
|
* @param clerkId - Clerk user identifier
|
|
220
222
|
* @returns User or null if not found
|
|
221
223
|
*/
|
|
222
|
-
async findByClerkId(clerkId: string): Promise<
|
|
224
|
+
async findByClerkId(clerkId: string): Promise<UserInfo | null> {
|
|
223
225
|
const { data, error } = await this.supabase
|
|
224
226
|
.from("users")
|
|
225
227
|
.select("*")
|
|
@@ -234,7 +236,7 @@ export class UserRepository implements IUserRepository {
|
|
|
234
236
|
* @param address - Wallet address
|
|
235
237
|
* @returns User or null if not found
|
|
236
238
|
*/
|
|
237
|
-
async findByWalletAddress(address: string): Promise<
|
|
239
|
+
async findByWalletAddress(address: string): Promise<UserInfo | null> {
|
|
238
240
|
const { data: accountData, error: accountError } = await this.supabase
|
|
239
241
|
.from("connected_accounts")
|
|
240
242
|
.select("user_id")
|
|
@@ -252,7 +254,7 @@ export class UserRepository implements IUserRepository {
|
|
|
252
254
|
* @param status - Onboarding status ('completed' | 'pending' | 'skipped')
|
|
253
255
|
* @returns Updated user
|
|
254
256
|
*/
|
|
255
|
-
async updateOnboardingStatus(userId: string, status: string): Promise<
|
|
257
|
+
async updateOnboardingStatus(userId: string, status: string): Promise<UserInfo> {
|
|
256
258
|
const updateData: Partial<AuthUser> = {
|
|
257
259
|
updatedAt: new Date(),
|
|
258
260
|
};
|
|
@@ -274,7 +276,7 @@ export class UserRepository implements IUserRepository {
|
|
|
274
276
|
* @private
|
|
275
277
|
*/
|
|
276
278
|
private transformToDbFormat(
|
|
277
|
-
data: CreateUserData
|
|
279
|
+
data: CreateUserData
|
|
278
280
|
): Record<string, string | AUTHPROVIDER | undefined> {
|
|
279
281
|
return {
|
|
280
282
|
email: data.email,
|
|
@@ -313,7 +315,7 @@ export class UserRepository implements IUserRepository {
|
|
|
313
315
|
* Map database row to User interface
|
|
314
316
|
* @private
|
|
315
317
|
*/
|
|
316
|
-
private mapToUser(data:
|
|
318
|
+
private mapToUser(data: UserInfo): UserInfo {
|
|
317
319
|
return {
|
|
318
320
|
id: data.id,
|
|
319
321
|
email: data.email,
|
|
@@ -4,46 +4,9 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { NUMERIX } from "@plyaz/config";
|
|
7
|
-
import type {
|
|
7
|
+
import type { JWTManagerSignin, PasswordServiceSignin, SessionManagerSignin, SignInCredentials, SignInResult, UserRepositorySignin } from "@plyaz/types";
|
|
8
8
|
|
|
9
|
-
export interface SignInCredentials {
|
|
10
|
-
email: string;
|
|
11
|
-
password: string;
|
|
12
|
-
rememberMe?: boolean;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export interface SignInResult {
|
|
16
|
-
user: AuthUser;
|
|
17
|
-
tokens: AuthTokens;
|
|
18
|
-
requiresMFA?: boolean;
|
|
19
|
-
mfaToken?: string;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/** User repository type based on usage */
|
|
23
|
-
export interface UserRepositorySignin {
|
|
24
|
-
findByEmail(email: string): Promise<AuthUser | null>;
|
|
25
|
-
findById(userId: string): Promise<AuthUser | null>;
|
|
26
|
-
}
|
|
27
9
|
|
|
28
|
-
/** JWT manager type based on usage */
|
|
29
|
-
export interface JWTManagerSignin {
|
|
30
|
-
generateTokens(userId: string): Promise<AuthTokens>;
|
|
31
|
-
verifyToken(token: string): Promise<{ userId: string }>;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/** Session manager type based on usage */
|
|
35
|
-
export interface SessionManagerSignin {
|
|
36
|
-
createSession(session: {
|
|
37
|
-
userId: string;
|
|
38
|
-
expiresAt: Date;
|
|
39
|
-
metadata?: Record<string, true>;
|
|
40
|
-
}): Promise<void>;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/** Password service type based on usage */
|
|
44
|
-
export interface PasswordServiceSignin {
|
|
45
|
-
verify(password: string, passwordHash: string | undefined): Promise<boolean>;
|
|
46
|
-
}
|
|
47
10
|
|
|
48
11
|
export class SignInFlow {
|
|
49
12
|
constructor(
|
|
@@ -3,67 +3,22 @@
|
|
|
3
3
|
* @module @plyaz/auth/flows/sign-up
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import type {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export interface SignUpResult {
|
|
17
|
-
user: AuthUser;
|
|
18
|
-
tokens: AuthTokens;
|
|
19
|
-
requiresVerification?: boolean;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/** User repository type based on usage */
|
|
23
|
-
export interface UserRepositorySignUp {
|
|
24
|
-
findByEmail(email: string): Promise<AuthUser | null>;
|
|
25
|
-
create(data: {
|
|
26
|
-
email: string;
|
|
27
|
-
passwordHash: string;
|
|
28
|
-
firstName?: string;
|
|
29
|
-
lastName?: string;
|
|
30
|
-
metadata?: Record<string, string>;
|
|
31
|
-
emailVerified: boolean;
|
|
32
|
-
}): Promise<AuthUser>;
|
|
33
|
-
findById(userId: string): Promise<AuthUser>;
|
|
34
|
-
updateEmailVerification(
|
|
35
|
-
userId: string,
|
|
36
|
-
verified: boolean,
|
|
37
|
-
): Promise<AuthUser | null>;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/** JWT manager type based on usage */
|
|
41
|
-
export interface JWTManagerSignUp {
|
|
42
|
-
generateTokens(userId: string): Promise<AuthTokens>;
|
|
43
|
-
generateVerificationToken(userId: string): Promise<string>;
|
|
44
|
-
verifyToken(token: string): Promise<{ userId: string }>;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/** Password service type based on usage */
|
|
48
|
-
export interface PasswordServiceSignUp {
|
|
49
|
-
hash(password: string): Promise<string>;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/** Email service type based on usage */
|
|
53
|
-
export interface EmailService {
|
|
54
|
-
sendVerificationEmail(args: {
|
|
55
|
-
to: string;
|
|
56
|
-
token: string;
|
|
57
|
-
userId: string;
|
|
58
|
-
}): Promise<void>;
|
|
59
|
-
}
|
|
6
|
+
import type {
|
|
7
|
+
AuthUser,
|
|
8
|
+
EmailService,
|
|
9
|
+
JWTManagerSignUp,
|
|
10
|
+
PasswordServiceSignUp,
|
|
11
|
+
SignUpData,
|
|
12
|
+
SignUpResult,
|
|
13
|
+
UserRepositorySignUp,
|
|
14
|
+
} from "@plyaz/types";
|
|
60
15
|
|
|
61
16
|
export class SignUpFlow {
|
|
62
17
|
constructor(
|
|
63
18
|
private userRepository: UserRepositorySignUp,
|
|
64
19
|
private jwtManager: JWTManagerSignUp,
|
|
65
20
|
private passwordService: PasswordServiceSignUp,
|
|
66
|
-
private emailService: EmailService
|
|
21
|
+
private emailService: EmailService
|
|
67
22
|
) {}
|
|
68
23
|
|
|
69
24
|
async execute(data: SignUpData): Promise<SignUpResult> {
|
|
@@ -120,7 +75,7 @@ export class SignUpFlow {
|
|
|
120
75
|
const payload = await this.jwtManager.verifyToken(token);
|
|
121
76
|
const user = await this.userRepository.updateEmailVerification(
|
|
122
77
|
payload.userId,
|
|
123
|
-
true
|
|
78
|
+
true
|
|
124
79
|
);
|
|
125
80
|
|
|
126
81
|
if (!user) {
|
package/src/index.ts
CHANGED
|
@@ -43,11 +43,4 @@ export {
|
|
|
43
43
|
export * from "./server/middleware";
|
|
44
44
|
|
|
45
45
|
// Frontend (React)
|
|
46
|
-
export
|
|
47
|
-
export { useAuth } from "./client/hooks/useAuth";
|
|
48
|
-
export { useSession } from "./client/hooks/useSession";
|
|
49
|
-
export { useRBAC } from "./client/hooks/useRBAC";
|
|
50
|
-
export { useConnectedAccounts } from "./client/hooks/useConnectedAccounts";
|
|
51
|
-
export { usePermissions } from "./client/hooks/usePermissions";
|
|
52
|
-
export { useAuthStore } from "./client/store/auth.store";
|
|
53
|
-
export { ProtectedRoute } from "./client/components/ProtectedRoute";
|
|
46
|
+
export * from "./client"
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type {
|
|
2
|
+
AuthDeviceInfo,
|
|
2
3
|
AUTHPROVIDER,
|
|
3
4
|
AuthUser,
|
|
4
5
|
ConnectedAccount,
|
|
@@ -10,12 +11,12 @@ import { randomBytes } from "crypto";
|
|
|
10
11
|
import { supabase } from "./supabaseClient";
|
|
11
12
|
import { NUMERIX } from "@plyaz/config";
|
|
12
13
|
|
|
13
|
-
export interface DeviceInfo {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
}
|
|
14
|
+
// export interface DeviceInfo {
|
|
15
|
+
// ip: string;
|
|
16
|
+
// browser: string;
|
|
17
|
+
// os: string;
|
|
18
|
+
// userAgent: string;
|
|
19
|
+
// }
|
|
19
20
|
|
|
20
21
|
/**
|
|
21
22
|
* Create a new user
|
|
@@ -86,7 +87,7 @@ export async function updateLastLogin(userId: string): Promise<void> {
|
|
|
86
87
|
*/
|
|
87
88
|
export async function createUserSession(
|
|
88
89
|
userId: string,
|
|
89
|
-
deviceInfo:
|
|
90
|
+
deviceInfo: AuthDeviceInfo,
|
|
90
91
|
): Promise<Session & { accessToken: string }> {
|
|
91
92
|
const thirtyTwo = 32;
|
|
92
93
|
const accessToken = randomBytes(thirtyTwo).toString("hex");
|
|
@@ -3,29 +3,10 @@
|
|
|
3
3
|
* @module @plyaz/auth/providers/base/auth-provider
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import type { AuthTokens, AuthUser } from "@plyaz/types";
|
|
6
|
+
import type { AuthenticationProvider, AuthProviderConfig, AuthTokens, AuthUser } from "@plyaz/types";
|
|
7
7
|
|
|
8
|
-
export interface AuthProviderConfig {
|
|
9
|
-
clientId: string;
|
|
10
|
-
clientSecret: string;
|
|
11
|
-
redirectUri: string;
|
|
12
|
-
scopes?: string[];
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export interface AuthProvider {
|
|
16
|
-
readonly name: string;
|
|
17
|
-
readonly type: "oauth" | "traditional" | "web3";
|
|
18
|
-
|
|
19
|
-
initialize(config: AuthProviderConfig): Promise<void>;
|
|
20
|
-
authenticate(credentials: {
|
|
21
|
-
code: string;
|
|
22
|
-
}): Promise<{ user: AuthUser; tokens: AuthTokens }>;
|
|
23
|
-
refreshToken(refreshToken: string): Promise<AuthTokens>;
|
|
24
|
-
revokeToken(token: string): Promise<void>;
|
|
25
|
-
getUserProfile(accessToken: string): Promise<AuthUser>;
|
|
26
|
-
}
|
|
27
8
|
|
|
28
|
-
export abstract class BaseAuthProvider implements
|
|
9
|
+
export abstract class BaseAuthProvider implements AuthenticationProvider {
|
|
29
10
|
abstract readonly name: string;
|
|
30
11
|
abstract readonly type: "oauth" | "traditional" | "web3";
|
|
31
12
|
|
|
@@ -24,58 +24,12 @@
|
|
|
24
24
|
*/
|
|
25
25
|
|
|
26
26
|
import { NUMERIX } from "@plyaz/config";
|
|
27
|
-
import {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
/** Assignment ID */
|
|
34
|
-
id: string;
|
|
35
|
-
/** User ID */
|
|
36
|
-
userId: string;
|
|
37
|
-
/** Role ID or name */
|
|
38
|
-
roleId: string;
|
|
39
|
-
/** Assignment conditions */
|
|
40
|
-
conditions?: Record<string, string>;
|
|
41
|
-
/** Assignment expiration */
|
|
42
|
-
expiresAt?: Date;
|
|
43
|
-
/** Assignment reason */
|
|
44
|
-
reason?: string;
|
|
45
|
-
/** Assigned by user ID */
|
|
46
|
-
assignedBy?: string;
|
|
47
|
-
/** Assignment metadata */
|
|
48
|
-
metadata?: Record<string, string>;
|
|
49
|
-
/** Created at */
|
|
50
|
-
createdAt: Date;
|
|
51
|
-
/** Is active */
|
|
52
|
-
isActive: boolean;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Role condition evaluator function
|
|
57
|
-
*/
|
|
58
|
-
export type RoleConditionEvaluator = (
|
|
59
|
-
userId: string,
|
|
60
|
-
conditions: Record<string, string>,
|
|
61
|
-
context?: Record<string, string>,
|
|
62
|
-
) => Promise<boolean>;
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Dynamic roles configuration
|
|
66
|
-
*/
|
|
67
|
-
export interface DynamicRolesConfig {
|
|
68
|
-
/** Enable role expiration */
|
|
69
|
-
enableExpiration: boolean;
|
|
70
|
-
/** Default role TTL in seconds */
|
|
71
|
-
defaultTTL: number;
|
|
72
|
-
/** Enable condition evaluation */
|
|
73
|
-
enableConditions: boolean;
|
|
74
|
-
/** Maximum assignments per user */
|
|
75
|
-
maxAssignmentsPerUser: number;
|
|
76
|
-
/** Enable audit logging */
|
|
77
|
-
enableAuditLog: boolean;
|
|
78
|
-
}
|
|
27
|
+
import {
|
|
28
|
+
AUTH_EVENTS,
|
|
29
|
+
type DynamicRolesConfig,
|
|
30
|
+
type DynamicRoleAssignment,
|
|
31
|
+
type RoleConditionEvaluator,
|
|
32
|
+
} from "@plyaz/types";
|
|
79
33
|
|
|
80
34
|
/**
|
|
81
35
|
* Dynamic roles manager implementation
|
|
@@ -124,7 +78,7 @@ export class DynamicRoles {
|
|
|
124
78
|
conditions?: Record<string, string>,
|
|
125
79
|
expiresAt?: Date,
|
|
126
80
|
assignedBy?: string,
|
|
127
|
-
reason?: string
|
|
81
|
+
reason?: string
|
|
128
82
|
): Promise<string> {
|
|
129
83
|
// Check assignment limits
|
|
130
84
|
await this.enforceAssignmentLimits(userId);
|
|
@@ -183,7 +137,7 @@ export class DynamicRoles {
|
|
|
183
137
|
conditions?: Record<string, string>,
|
|
184
138
|
duration: number = this.config.defaultTTL,
|
|
185
139
|
assignedBy?: string,
|
|
186
|
-
reason?: string
|
|
140
|
+
reason?: string
|
|
187
141
|
): Promise<string> {
|
|
188
142
|
const expiresAt = new Date(Date.now() + duration * NUMERIX.THOUSAND);
|
|
189
143
|
|
|
@@ -193,7 +147,7 @@ export class DynamicRoles {
|
|
|
193
147
|
conditions,
|
|
194
148
|
expiresAt,
|
|
195
149
|
assignedBy,
|
|
196
|
-
reason ?? "Temporary assignment"
|
|
150
|
+
reason ?? "Temporary assignment"
|
|
197
151
|
);
|
|
198
152
|
}
|
|
199
153
|
|
|
@@ -206,7 +160,7 @@ export class DynamicRoles {
|
|
|
206
160
|
async revokeAssignment(
|
|
207
161
|
assignmentId: string,
|
|
208
162
|
revokedBy?: string,
|
|
209
|
-
reason?: string
|
|
163
|
+
reason?: string
|
|
210
164
|
): Promise<void> {
|
|
211
165
|
const assignment = this.assignments.get(assignmentId);
|
|
212
166
|
|
|
@@ -244,7 +198,7 @@ export class DynamicRoles {
|
|
|
244
198
|
async revokeAllUserAssignments(
|
|
245
199
|
userId: string,
|
|
246
200
|
revokedBy?: string,
|
|
247
|
-
reason?: string
|
|
201
|
+
reason?: string
|
|
248
202
|
): Promise<void> {
|
|
249
203
|
const userAssignmentSet = this.userAssignments.get(userId);
|
|
250
204
|
|
|
@@ -267,7 +221,7 @@ export class DynamicRoles {
|
|
|
267
221
|
*/
|
|
268
222
|
async getUserRoles(
|
|
269
223
|
userId: string,
|
|
270
|
-
context?: Record<string, string
|
|
224
|
+
context?: Record<string, string>
|
|
271
225
|
): Promise<string[]> {
|
|
272
226
|
const userAssignmentSet = this.userAssignments.get(userId);
|
|
273
227
|
|
|
@@ -296,7 +250,7 @@ export class DynamicRoles {
|
|
|
296
250
|
const conditionsMet = await this.evaluateConditions(
|
|
297
251
|
userId,
|
|
298
252
|
assignment.conditions,
|
|
299
|
-
context
|
|
253
|
+
context
|
|
300
254
|
);
|
|
301
255
|
|
|
302
256
|
if (!conditionsMet) {
|
|
@@ -320,7 +274,7 @@ export class DynamicRoles {
|
|
|
320
274
|
async hasRole(
|
|
321
275
|
userId: string,
|
|
322
276
|
roleId: string,
|
|
323
|
-
context?: Record<string, string
|
|
277
|
+
context?: Record<string, string>
|
|
324
278
|
): Promise<boolean> {
|
|
325
279
|
const userRoles = await this.getUserRoles(userId, context);
|
|
326
280
|
return userRoles.includes(roleId);
|
|
@@ -343,7 +297,7 @@ export class DynamicRoles {
|
|
|
343
297
|
*/
|
|
344
298
|
getUserAssignments(
|
|
345
299
|
userId: string,
|
|
346
|
-
includeInactive = false
|
|
300
|
+
includeInactive = false
|
|
347
301
|
): DynamicRoleAssignment[] {
|
|
348
302
|
const userAssignmentSet = this.userAssignments.get(userId);
|
|
349
303
|
|
|
@@ -371,7 +325,7 @@ export class DynamicRoles {
|
|
|
371
325
|
*/
|
|
372
326
|
registerConditionEvaluator(
|
|
373
327
|
conditionType: string,
|
|
374
|
-
evaluator: RoleConditionEvaluator
|
|
328
|
+
evaluator: RoleConditionEvaluator
|
|
375
329
|
): void {
|
|
376
330
|
this.conditionEvaluators.set(conditionType, evaluator);
|
|
377
331
|
}
|
|
@@ -383,7 +337,7 @@ export class DynamicRoles {
|
|
|
383
337
|
*/
|
|
384
338
|
async extendAssignment(
|
|
385
339
|
assignmentId: string,
|
|
386
|
-
newExpiresAt: Date
|
|
340
|
+
newExpiresAt: Date
|
|
387
341
|
): Promise<void> {
|
|
388
342
|
const assignment = this.assignments.get(assignmentId);
|
|
389
343
|
|
|
@@ -482,7 +436,7 @@ export class DynamicRoles {
|
|
|
482
436
|
private async evaluateConditions(
|
|
483
437
|
userId: string,
|
|
484
438
|
conditions: Record<string, string>,
|
|
485
|
-
context?: Record<string, string
|
|
439
|
+
context?: Record<string, string>
|
|
486
440
|
): Promise<boolean> {
|
|
487
441
|
for (const [conditionType, conditionValue] of Object.entries(conditions)) {
|
|
488
442
|
const evaluator = this.conditionEvaluators.get(conditionType);
|
|
@@ -491,7 +445,7 @@ export class DynamicRoles {
|
|
|
491
445
|
const result = await evaluator(
|
|
492
446
|
userId,
|
|
493
447
|
{ [conditionType]: conditionValue },
|
|
494
|
-
context
|
|
448
|
+
context
|
|
495
449
|
);
|
|
496
450
|
if (!result) {
|
|
497
451
|
return false;
|
|
@@ -517,7 +471,7 @@ export class DynamicRoles {
|
|
|
517
471
|
|
|
518
472
|
if (userAssignments.length >= this.config.maxAssignmentsPerUser) {
|
|
519
473
|
throw new Error(
|
|
520
|
-
`Maximum assignments per user exceeded: ${this.config.maxAssignmentsPerUser}
|
|
474
|
+
`Maximum assignments per user exceeded: ${this.config.maxAssignmentsPerUser}`
|
|
521
475
|
);
|
|
522
476
|
}
|
|
523
477
|
}
|
|
@@ -541,7 +495,7 @@ export class DynamicRoles {
|
|
|
541
495
|
async () => {
|
|
542
496
|
await this.cleanupExpiredAssignments();
|
|
543
497
|
},
|
|
544
|
-
NUMERIX.FIVE * NUMERIX.SIXTY * NUMERIX.THOUSAND
|
|
498
|
+
NUMERIX.FIVE * NUMERIX.SIXTY * NUMERIX.THOUSAND
|
|
545
499
|
);
|
|
546
500
|
}
|
|
547
501
|
|
|
@@ -571,7 +525,7 @@ export class DynamicRoles {
|
|
|
571
525
|
private emitRoleRevokedEvent(
|
|
572
526
|
assignment: DynamicRoleAssignment,
|
|
573
527
|
revokedBy?: string,
|
|
574
|
-
reason?: string
|
|
528
|
+
reason?: string
|
|
575
529
|
): void {
|
|
576
530
|
// Mock event emission - in real implementation would use event system
|
|
577
531
|
globalThis.console.log(`Event: ${AUTH_EVENTS.ROLE_REVOKED}`, {
|