From 3760b4ab180bcdfbd12d6a96a81aef3f40d76511 Mon Sep 17 00:00:00 2001 From: Soubhik Kumar Gon Date: Sat, 16 Mar 2024 00:40:40 +0530 Subject: [PATCH] feat: adds auth data from other collections during user login --- apis/src/authentication.ts | 84 ++++++++++++++++++- apis/src/hooks/block-cross-delete.ts | 21 +++++ apis/src/models/platform-super-admin.model.ts | 10 +-- apis/src/models/player.model.ts | 3 +- apis/src/services/player/player.hooks.ts | 4 +- apis/src/services/users/users.class.ts | 3 +- .../users/verification/verification.class.ts | 17 ++-- .../users/verification/verification.hooks.ts | 9 +- 8 files changed, 126 insertions(+), 25 deletions(-) create mode 100644 apis/src/hooks/block-cross-delete.ts diff --git a/apis/src/authentication.ts b/apis/src/authentication.ts index d95d01c..afb67d3 100644 --- a/apis/src/authentication.ts +++ b/apis/src/authentication.ts @@ -1,9 +1,14 @@ -import { ServiceAddons } from '@feathersjs/feathers'; +import { HookContext, Paginated, Params, ServiceAddons } from '@feathersjs/feathers'; import { AuthenticationService, JWTStrategy } from '@feathersjs/authentication'; import { LocalStrategy } from '@feathersjs/authentication-local'; import { expressOauth } from '@feathersjs/authentication-oauth'; import { Application } from './declarations'; +import { Users } from './services/users/users.class'; +import RolesEnum from './constants/roles.enum'; +import { Player } from './services/player/player.class'; +import { PlatformSuperAdmin } from './services/platform-super-admin/platform-super-admin.class'; +import { Admin } from './services/admin/admin.class'; declare module './declarations' { interface ServiceTypes { @@ -11,12 +16,85 @@ declare module './declarations' { } } -export default function(app: Application): void { +export default function (app: Application): void { const authentication = new AuthenticationService(app); + class CustomLocalStrategy extends LocalStrategy { + async findEntity(username: string, params: Params): Promise { + // Find the user entity + console.log(`username = ${username}`) + const UserService: Users & ServiceAddons = app.service('users'); + const user: any[] | Paginated = await UserService.find({ + query: { email: username }, + paginate: false // To get only one user + }); + // @ts-ignore + if (user.length === 0) { + return null; // User not found + } + + // Get the first user (assuming email is unique) + // @ts-ignore + const foundUser = user[0]; + return { ...foundUser }; + } + } + authentication.register('jwt', new JWTStrategy()); - authentication.register('local', new LocalStrategy()); + authentication.register('local', new CustomLocalStrategy()); app.use('/authentication', authentication); app.configure(expressOauth()); + const service = app.service('authentication'); + + service.hooks({ + after: { + create: [ + async (context: HookContext) => { + const { user } = context.result; + console.log(user); + + if (user.role === RolesEnum.PLAYER) { + // Load player data + let playerData = null; + const playerService: Player & ServiceAddons = app.service('player'); + const player = await playerService._find({ + query: { user: user._id }, + paginate: false + }); + playerData = player.length > 0 ? player[0] : null; + + console.log(playerData) + context.result.user.playerData = playerData; + } + + if (user.role === RolesEnum.ADMIN) { + let adminData = null; + const adminService: Admin & ServiceAddons = app.service('admin'); + const psa = await adminService._find({ + query: { user: user._id }, + paginate: false + }); + + adminData = psa.length > 0 ? psa[0] : null; + console.log(adminData) + context.result.user.adminData = adminData; + } + + if (user.role === RolesEnum.PLATFORM_SUPER_ADMIN) { + let psaData = null; + const psaService: PlatformSuperAdmin & ServiceAddons = app.service('platform-super-admin'); + const psa = await psaService._find({ + query: { user: user._id }, + paginate: false + }); + psaData = psa.length > 0 ? psa[0] : null; + + console.log(psaData) + context.result.user.psaData = psaData; + } + } + ] + } + }); } diff --git a/apis/src/hooks/block-cross-delete.ts b/apis/src/hooks/block-cross-delete.ts new file mode 100644 index 0000000..9b39bae --- /dev/null +++ b/apis/src/hooks/block-cross-delete.ts @@ -0,0 +1,21 @@ +// Use this hook to manipulate incoming or outgoing data. +// For more information on hooks see: http://docs.feathersjs.com/api/hooks.html +import { BadRequest } from '@feathersjs/errors'; +import { Hook, HookContext } from '@feathersjs/feathers'; +import RolesEnum from '../constants/roles.enum'; + +// eslint-disable-next-line @typescript-eslint/no-unused-vars +export default (options: object = {}): Hook => { + return async (context: HookContext): Promise => { + + + const targetId = context.id; + const { user } = context.params; + // @ts-ignore + if(user.role === RolesEnum.PLATFORM_SUPER_ADMIN) return context + // @ts-ignore + const initiatorId = user._id.toString(); + if(initiatorId === targetId) return context; + throw new BadRequest('users cannot delete other users') + }; +}; diff --git a/apis/src/models/platform-super-admin.model.ts b/apis/src/models/platform-super-admin.model.ts index 5fccd50..e9a97a5 100644 --- a/apis/src/models/platform-super-admin.model.ts +++ b/apis/src/models/platform-super-admin.model.ts @@ -14,15 +14,7 @@ export default function (app: Application): Model { type: mongoose.Schema.Types.ObjectId, ref: 'users', required: true, - }, - contactNo: { - type: String - }, - socials: [ - { - type: Object - } - ], + } }, { timestamps: true }); diff --git a/apis/src/models/player.model.ts b/apis/src/models/player.model.ts index b916d56..062bb96 100644 --- a/apis/src/models/player.model.ts +++ b/apis/src/models/player.model.ts @@ -39,7 +39,8 @@ export default function (app: Application): Model { ref: 'player' }, deletedAt: { - type: Date + type: Date, + default:Date.now() }, }, { timestamps: true diff --git a/apis/src/services/player/player.hooks.ts b/apis/src/services/player/player.hooks.ts index 4330229..0ec787d 100644 --- a/apis/src/services/player/player.hooks.ts +++ b/apis/src/services/player/player.hooks.ts @@ -1,5 +1,7 @@ import { HooksObject } from '@feathersjs/feathers'; import * as authentication from '@feathersjs/authentication'; +import BlockCrossDelete from '../../hooks/block-cross-delete'; +import { discard } from 'feathers-hooks-common'; // Don't remove this comment. It's needed to format import lines nicely. const { authenticate } = authentication.hooks; @@ -12,7 +14,7 @@ export default { create: [], update: [], patch: [], - remove: [] + remove: [BlockCrossDelete()] }, after: { diff --git a/apis/src/services/users/users.class.ts b/apis/src/services/users/users.class.ts index 2adeea4..0466570 100644 --- a/apis/src/services/users/users.class.ts +++ b/apis/src/services/users/users.class.ts @@ -20,8 +20,9 @@ export class Users extends Service { const otp = generateOTP(); const secret = app.settings.authentication.secret; data.role = RolesEnum.PLAYER; + console.log(data) const token = jwt.sign({ - player: data, + user: data, otp }, secret); diff --git a/apis/src/services/users/verification/verification.class.ts b/apis/src/services/users/verification/verification.class.ts index 925fe24..f7e1bed 100644 --- a/apis/src/services/users/verification/verification.class.ts +++ b/apis/src/services/users/verification/verification.class.ts @@ -4,7 +4,7 @@ import { extractTokenFromHeader } from '../../../utils/extractTokenFromHeader'; import { BadRequest } from '@feathersjs/errors'; import { Service } from 'feathers-mongoose'; import { Users } from '../users.class'; - +import * as jwt from "jsonwebtoken" interface Data { } interface ServiceOptions { } @@ -43,16 +43,19 @@ export class Verification implements ServiceMethods { const secret = this.app.settings.authentication.secret; // @ts-ignore - const { player, otp } = jwt.decode(token, secret); - console.log('player = ', player); - if (!player) throw new BadRequest('Invalid Token'); + + const decodedVal = jwt.decode(token, secret); + console.log(decodedVal) + // @ts-ignore + const { user, otp } = decodedVal + console.log('user = ', user); + if (!user) throw new BadRequest('Invalid Token'); // @ts-ignore if (otp === data.otp) { const UserService: Users & ServiceAddons = this.app.service('users'); - console.log(player); - const user = await UserService._create(player); - return user + console.log(user); + return await UserService._create(user); } else throw new Error('OTP is invalid'); } catch (error: any) { diff --git a/apis/src/services/users/verification/verification.hooks.ts b/apis/src/services/users/verification/verification.hooks.ts index 4330229..97c4a0d 100644 --- a/apis/src/services/users/verification/verification.hooks.ts +++ b/apis/src/services/users/verification/verification.hooks.ts @@ -1,12 +1,13 @@ import { HooksObject } from '@feathersjs/feathers'; +import * as local from '@feathersjs/authentication-local'; import * as authentication from '@feathersjs/authentication'; // Don't remove this comment. It's needed to format import lines nicely. const { authenticate } = authentication.hooks; - +const { hashPassword, protect } = local.hooks; export default { before: { - all: [ authenticate('jwt') ], + all: [], find: [], get: [], create: [], @@ -16,7 +17,9 @@ export default { }, after: { - all: [], + all: [ + protect('password') + ], find: [], get: [], create: [],