114 lines
3.5 KiB
TypeScript
114 lines
3.5 KiB
TypeScript
import { Inject, Injectable } from '@nestjs/common';
|
|
import * as admin from 'firebase-admin';
|
|
import { FirebaseUserInfo, UserRole } from 'src/models/main.model';
|
|
|
|
@Injectable()
|
|
export class AuthService {
|
|
constructor(@Inject('FIREBASE_ADMIN') private firebaseAdmin: admin.app.App) {}
|
|
|
|
/**
|
|
* Set a user's role via Firebase custom claims
|
|
*/
|
|
async setUserRole(uid: string, role: UserRole): Promise<void> {
|
|
try {
|
|
// Get the current custom claims
|
|
const user = await this.firebaseAdmin.auth().getUser(uid);
|
|
const currentClaims = user.customClaims || {};
|
|
|
|
// Set the new role
|
|
await this.firebaseAdmin.auth().setCustomUserClaims(uid, {
|
|
...currentClaims,
|
|
role: role,
|
|
});
|
|
} catch (error) {
|
|
console.error('Error setting user role:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get a user's current role
|
|
*/
|
|
async getUserRole(uid: string): Promise<UserRole | null> {
|
|
try {
|
|
const user = await this.firebaseAdmin.auth().getUser(uid);
|
|
const claims = user.customClaims || {};
|
|
return (claims.role as UserRole) || null;
|
|
} catch (error) {
|
|
console.error('Error getting user role:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get all users with a specific role
|
|
*/
|
|
async getUsersByRole(role: UserRole): Promise<admin.auth.UserRecord[]> {
|
|
// Note: Firebase Admin doesn't provide a direct way to query users by custom claims
|
|
// For a production app, you might want to store role information in Firestore as well
|
|
// This is a simple implementation that lists all users and filters them
|
|
try {
|
|
const listUsersResult = await this.firebaseAdmin.auth().listUsers();
|
|
return listUsersResult.users.filter(user => user.customClaims && user.customClaims.role === role);
|
|
} catch (error) {
|
|
console.error('Error getting users by role:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get all Firebase users with their roles
|
|
* @param maxResults Maximum number of users to return (optional, default 1000)
|
|
* @param pageToken Token for pagination (optional)
|
|
*/
|
|
async getAllUsers(maxResults: number = 1000, pageToken?: string): Promise<{ users: FirebaseUserInfo[]; pageToken?: string }> {
|
|
try {
|
|
const listUsersResult = await this.firebaseAdmin.auth().listUsers(maxResults, pageToken);
|
|
|
|
const users = listUsersResult.users.map(user => this.mapUserRecord(user));
|
|
|
|
return {
|
|
users,
|
|
pageToken: listUsersResult.pageToken,
|
|
};
|
|
} catch (error) {
|
|
console.error('Error getting all users:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
/**
|
|
* Maps a Firebase UserRecord to our FirebaseUserInfo interface
|
|
*/
|
|
private mapUserRecord(user: admin.auth.UserRecord): FirebaseUserInfo {
|
|
return {
|
|
uid: user.uid,
|
|
email: user.email || null,
|
|
displayName: user.displayName || null,
|
|
photoURL: user.photoURL || null,
|
|
phoneNumber: user.phoneNumber || null,
|
|
disabled: user.disabled,
|
|
emailVerified: user.emailVerified,
|
|
role: user.customClaims?.role || null,
|
|
creationTime: user.metadata.creationTime,
|
|
lastSignInTime: user.metadata.lastSignInTime,
|
|
// Optionally include other customClaims if needed
|
|
customClaims: user.customClaims,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Set default role for a new user
|
|
*/
|
|
async setDefaultRole(uid: string): Promise<void> {
|
|
return this.setUserRole(uid, 'guest');
|
|
}
|
|
|
|
/**
|
|
* Verify if a user has a specific role
|
|
*/
|
|
async hasRole(uid: string, role: UserRole): Promise<boolean> {
|
|
const userRole = await this.getUserRole(uid);
|
|
return userRole === role;
|
|
}
|
|
}
|