-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #24 from fless-lab/feat/advanced-f-structure
feat: Introduced core plugins and middlewares for authentication and user context
- Loading branch information
Showing
28 changed files
with
635 additions
and
43 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
https://documenter.getpostman.com/view/15120939/2sA3kUGMx7 | ||
|
||
|
||
Feel free to let comments is something going wrong |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
/** | ||
* Ceci c'est juste un exemple de plugin | ||
*/ | ||
|
||
import { Schema } from 'mongoose'; | ||
|
||
export const attemptLimitingPlugin = ( | ||
schema: Schema, | ||
options?: { maxAttempts?: number }, | ||
) => { | ||
schema.add({ attempts: { type: Number, default: 0 } }); | ||
|
||
schema.methods.incrementAttempts = async function () { | ||
this.attempts += 1; | ||
const maxAttempts = options?.maxAttempts || 3; | ||
|
||
if (this.attempts >= maxAttempts) { | ||
this.used = true; | ||
this.isFresh = false; | ||
} | ||
await this.save(); | ||
}; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from './attemp-limiting.plugin'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,17 +1,17 @@ | ||
import { Document } from 'mongoose'; | ||
import { Document, Types } from 'mongoose'; | ||
import { config } from '../../../core/config'; | ||
import { IBaseModel } from '../../../core/engine'; | ||
|
||
export type TOTPPurpose = keyof typeof config.otp.purposes; | ||
|
||
export interface IOTP { | ||
code: string; | ||
user: string; | ||
user: Types.ObjectId; | ||
used: boolean; | ||
isFresh: boolean; | ||
expiresAt: Date; | ||
purpose: TOTPPurpose; | ||
createdAt?: Date; | ||
updatedAt?: Date; | ||
attempts?: number; | ||
} | ||
|
||
export interface IOTPModel extends IOTP, Document {} | ||
export interface IOTPModel extends IOTP, IBaseModel, Document {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,24 @@ | ||
import { Router } from 'express'; | ||
import { authenticateRequest, validate } from '../../../common/shared'; | ||
import { | ||
authenticateAndAttachUserContext, | ||
validate, | ||
} from '../../../common/shared'; | ||
import { createUserSchema } from '../validators'; | ||
import { UserController } from '../controllers'; | ||
const router = Router(); | ||
|
||
router.post('/', validate(createUserSchema), UserController.createUser); | ||
router.post( | ||
'/', | ||
authenticateAndAttachUserContext, | ||
validate(createUserSchema), | ||
UserController.createUser, | ||
); | ||
router.get('/', UserController.getAllUsers); | ||
router.get('/current', authenticateRequest, UserController.getCurrentUser); | ||
router.get( | ||
'/current', | ||
authenticateAndAttachUserContext, | ||
UserController.getCurrentUser, | ||
); | ||
router.get('/:id', UserController.getUserById); | ||
|
||
export default router; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import { Request, Response, NextFunction } from 'express'; | ||
import { AsyncStorageService, logger } from '../services'; | ||
|
||
export const attachUserToContext = ( | ||
req: Request, | ||
res: Response, | ||
next: NextFunction, | ||
) => { | ||
const asyncStorage = AsyncStorageService.getInstance(); | ||
// @ts-ignore: Suppress TS error for non-existent property | ||
const payload = req.payload; | ||
if (payload && typeof payload.aud === 'string') { | ||
const userId = payload.aud; | ||
|
||
asyncStorage.run(() => { | ||
asyncStorage.set('currentUserId', userId); | ||
next(); | ||
}); | ||
} else { | ||
logger.warn( | ||
'Warning: Unable to attach user context, missing payload or audience field.', | ||
); | ||
next(); | ||
} | ||
}; |
32 changes: 32 additions & 0 deletions
32
src/common/shared/middlewares/authenticate-req-with-user-attach.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import { Request, Response, NextFunction } from 'express'; | ||
import { JwtService, AsyncStorageService, logger } from '../services'; | ||
|
||
export const authenticateAndAttachUserContext = ( | ||
req: Request, | ||
res: Response, | ||
next: NextFunction, | ||
) => { | ||
JwtService.verifyAccessToken(req, res, (authErr: any) => { | ||
if (authErr) { | ||
return next(authErr); | ||
} | ||
|
||
// @ts-ignore: Suppress TS error for non-existent property | ||
const payload = req.payload; | ||
|
||
if (payload && typeof payload.aud === 'string') { | ||
const userId = payload.aud; | ||
const asyncStorage = AsyncStorageService.getInstance(); | ||
|
||
asyncStorage.run(() => { | ||
asyncStorage.set('currentUserId', userId); | ||
next(); | ||
}); | ||
} else { | ||
logger.warn( | ||
'Warning: Unable to attach user context, missing payload or audience field.', | ||
); | ||
next(); | ||
} | ||
}); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import { AsyncLocalStorage } from 'async_hooks'; | ||
|
||
export class AsyncStorageService { | ||
private static instance: AsyncStorageService; | ||
private storage: AsyncLocalStorage<Map<string, any>>; | ||
|
||
private constructor() { | ||
this.storage = new AsyncLocalStorage(); | ||
} | ||
|
||
public static getInstance(): AsyncStorageService { | ||
if (!AsyncStorageService.instance) { | ||
AsyncStorageService.instance = new AsyncStorageService(); | ||
} | ||
return AsyncStorageService.instance; | ||
} | ||
|
||
public set(key: string, value: any) { | ||
const store = this.storage.getStore(); | ||
if (store) { | ||
store.set(key, value); | ||
} | ||
} | ||
|
||
public get(key: string): any { | ||
const store = this.storage.getStore(); | ||
return store ? store.get(key) : undefined; | ||
} | ||
|
||
public run(callback: () => void, initialValue?: Map<string, any>) { | ||
this.storage.run(initialValue || new Map(), callback); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
32 changes: 32 additions & 0 deletions
32
src/core/engine/base/_models/_plugins/audit-trail.plugin.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import { Schema } from 'mongoose'; | ||
import { AsyncStorageService, logger } from '../../../../../common/shared'; | ||
|
||
const auditTrailPlugin = (schema: Schema) => { | ||
schema.pre('save', function (next) { | ||
const currentUserId = | ||
AsyncStorageService.getInstance().get('currentUserId'); | ||
|
||
if (!currentUserId) { | ||
logger.warn( | ||
'Warning: currentUserId is undefined. Audit trail fields will not be set.', | ||
); | ||
} | ||
|
||
if (this.isNew) { | ||
this.set('createdBy', currentUserId || null); | ||
} else { | ||
this.set('updatedBy', currentUserId || null); | ||
} | ||
next(); | ||
}); | ||
|
||
schema.methods.softDelete = function () { | ||
const currentUserId = | ||
AsyncStorageService.getInstance().get('currentUserId'); | ||
this.deletedAt = new Date(); | ||
this.deletedBy = currentUserId || null; | ||
return this.save(); | ||
}; | ||
}; | ||
|
||
export default auditTrailPlugin; |
Oops, something went wrong.