Skip to content

Commit

Permalink
[FEATURE]: created the bff part of the authentication (#24)
Browse files Browse the repository at this point in the history
  • Loading branch information
helabenkhalfallah authored Nov 26, 2024
2 parents 2cffd1b + b368732 commit cbd51fd
Show file tree
Hide file tree
Showing 29 changed files with 1,370 additions and 53 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -139,4 +139,5 @@ database/psql/**
**/jest-cache/**
**/jest-stare/**
**/v6y-logs/**
**/coverage**
.vscode/
**/coverage**
422 changes: 391 additions & 31 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion src/v6y-bff/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
"express": "=4.18.2",
"express-status-monitor": "=1.3.4",
"graphql": "=16.5.0",
"graphql-tag": "=2.12.6"
"graphql-tag": "=2.12.6",
"passport": "= 0.7.0"
}
}
19 changes: 5 additions & 14 deletions src/v6y-bff/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
import { ApolloServer } from '@apollo/server';
import { expressMiddleware } from '@apollo/server/express4';
import { ApolloServerPluginDrainHttpServer } from '@apollo/server/plugin/drainHttpServer';
import { AppLogger, DataBaseManager, ServerUtils } from '@v6y/commons';
import BodyParser from 'body-parser';
import Cors from 'cors';
import { AppLogger, DataBaseManager, ServerUtils, passportInitialize } from '@v6y/commons';
import Express from 'express';
import ExpressStatusMonitor from 'express-status-monitor';

import ServerConfig from './config/ServerConfig.ts';
import VitalityResolvers from './resolvers/VitalityResolvers.ts';
import { buildUserMiddleware } from './resolvers/manager/AuthenticationManager.ts';
import VitalityTypes from './types/VitalityTypes.ts';

const { createServer } = ServerUtils;
Expand Down Expand Up @@ -37,6 +35,8 @@ app.use(

// *********************************************** Graphql Config & Endpoints ***********************************************

app.use(passportInitialize());

const httpServer = createServer({
app,
config: getCurrentConfig(),
Expand All @@ -54,16 +54,7 @@ const server = new ApolloServer({

await server.start();

app.use(
apiPath as string,
Cors(),
BodyParser.json(),
expressMiddleware(server, {
context: async ({ req }) => ({
token: req.headers.token,
}),
}),
);
app.use(...buildUserMiddleware(server, apiPath as string));

// *********************************************** Health Check Endpoints ***********************************************

Expand Down
3 changes: 3 additions & 0 deletions src/v6y-bff/src/resolvers/VitalityResolvers.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import AccountResolvers from './account/AccountResolvers.ts';
import ApplicationResolvers from './application/ApplicationResolvers.ts';
import AuditHelpResolvers from './audit/AuditHelpResolvers.ts';
import DeprecatedDependencyResolvers from './dependency/deprecated-status/DeprecatedDependencyResolvers.ts';
Expand All @@ -8,6 +9,7 @@ import NotificationsResolvers from './notifications/NotificationsResolvers.ts';

const VitalityResolvers = {
Query: {
...AccountResolvers.Query,
...ApplicationResolvers.Query,
...FaqResolvers.Query,
...NotificationsResolvers.Query,
Expand All @@ -17,6 +19,7 @@ const VitalityResolvers = {
...DeprecatedDependencyResolvers.Query,
},
Mutation: {
...AccountResolvers.Mutation,
...ApplicationResolvers.Mutation,
...FaqResolvers.Mutation,
...NotificationsResolvers.Mutation,
Expand Down
108 changes: 108 additions & 0 deletions src/v6y-bff/src/resolvers/account/AccountMutations.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import {
AccountInputType,
AccountProvider,
AppLogger,
PasswordUtils,
SearchQueryType,
} from '@v6y/commons';

const { hashPassword } = PasswordUtils;

/**
* Create or edit account
* @param _
* @param params
*/
const createOrEditAccount = async (_: unknown, params: { accountInput: AccountInputType }) => {
try {
const { _id, username, password, email, role, applications } = params?.accountInput || {};

AppLogger.info(`[AccountMutations - createOrEditAccount] _id : ${_id}`);
AppLogger.info(`[AccountMutations - createOrEditAccount] username : ${username}`);
AppLogger.info(`[AccountMutations - createOrEditAccount] password : ${password}`);
AppLogger.info(`[AccountMutations - createOrEditAccount] email : ${email}`);
AppLogger.info(`[AccountMutations - createOrEditAccount] role : ${role}`);
AppLogger.info(
`[AccountMutations - createOrEditAccount] applications : ${applications?.join(',')}`,
);

if (_id) {
const editedAccount = await AccountProvider.editAccount({
_id,
username,
password: await hashPassword(password),
email,
role,
applications,
});

if (!editedAccount || !editedAccount._id) {
return null;
}

AppLogger.info(
`[AccountMutations - createOrEditAccount] editedAccount : ${editedAccount?._id}`,
);

return {
_id: editedAccount._id,
};
}

const createdAccount = await AccountProvider.createAccount({
username,
password: await hashPassword(password),
email,
role,
applications,
});

if (!createdAccount || !createdAccount._id) {
return null;
}

AppLogger.info(
`[AccountMutations - createOrEditAccount] createdAccount : ${createdAccount?._id}`,
);

return {
_id: createdAccount._id,
};
} catch (error) {
AppLogger.info(`[AccountMutations - createOrEditAccount] error : ${error}`);
return null;
}
};

/**
* Delete account
* @param _
* @param params
*/
const deleteAccount = async (_: unknown, params: { input: SearchQueryType }) => {
try {
const whereClause = params?.input?.where;
if (!whereClause) {
return null;
}

const accountId = whereClause._id;
AppLogger.info(`[AccountMutations - deleteAccount] accountId : ${accountId}`);

await AccountProvider.deleteAccount({ _id: accountId });
AppLogger.info(`[AccountMutations - deleteAccount] deleted account : ${accountId}`);
return {
_id: accountId,
};
} catch (error) {
AppLogger.info(`[AccountMutations - deleteAccount] error : ${error}`);
return null;
}
};

const AccountMutations = {
createOrEditAccount,
deleteAccount,
};

export default AccountMutations;
126 changes: 126 additions & 0 deletions src/v6y-bff/src/resolvers/account/AccountQueries.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import {
AccountLoginType,
AccountProvider,
AccountType,
AppLogger,
PasswordUtils,
SearchQueryType,
passportGenerateToken,
} from '@v6y/commons';

const { validatePassword } = PasswordUtils;

/**
* Fetch the Account details by parameters
* @param _
* @param args
*/
const getAccountDetailsByParams = async (_: unknown, args: AccountType) => {
try {
const { _id } = args || {};

AppLogger.info(`[AccountQueries - getAccountDetailsByParams] _id : ${_id}`);

if (!_id) {
return null;
}

const accountDetails = await AccountProvider.getAccountDetailsByParams({
_id,
});

AppLogger.info(
`[AccountQueries - getAccountDetailsByParams] accountDetails : ${accountDetails?._id}`,
);

return accountDetails;
} catch (error) {
AppLogger.info(`[AccountQueries - getAccountDetailsByParams] error : ${error}`);
return null;
}
};

/**
* Fetch the Account list by page and parameters
* @param _
* @param args
*/
const getAccountListByPageAndParams = async (_: unknown, args: SearchQueryType) => {
try {
const { searchText, start, limit, sort } = args || {};

// Log the input parameters for debugging/tracking purposes
AppLogger.info(`[AccountQueries - getAccountListByPageAndParams] start : ${start}`);
AppLogger.info(`[AccountQueries - getAccountListByPageAndParams] limit : ${limit}`);
AppLogger.info(`[AccountQueries - getAccountListByPageAndParams] sort : ${sort}`);

// Fetch the Account list (Note: the provided arguments are not being used in the call)
const accountList = await AccountProvider.getAccountListByPageAndParams({
searchText,
start,
limit,
sort,
});

AppLogger.info(
`[AccountQueries - getAccountListByPageAndParams] accountList : ${accountList?.length}`,
);

return accountList;
} catch (error) {
AppLogger.error(`[AccountQueries - getFaqListByPageAndParams] error : ${error}`);
return [];
}
};

/**
* Login account
* @param _
* @param paramsc
*/
const loginAccount = async (_: unknown, params: { input: AccountLoginType }) => {
try {
const { email, password } = params?.input || {};
AppLogger.info(`[AccountMutations - loginAccount] username : ${email}`);

if (!email || !password) {
return null;
}

const accountDetails = await AccountProvider.getAccountDetailsByParams({
email,
});

AppLogger.info(`[AccountMutations - loginAccount] accountDetails : ${accountDetails?._id}`);

if (!accountDetails || !accountDetails.password || !accountDetails._id) {
return null;
}

const isPasswordMatch = await validatePassword(password, accountDetails.password);

if (!isPasswordMatch) {
return null;
}

const token = passportGenerateToken(accountDetails);

AppLogger.info(`[AccountMutations - loginAccount] login success : ${accountDetails._id}`);

return {
_id: accountDetails._id,
token,
};
} catch (error) {
AppLogger.info(`[AccountMutations - loginAccount] error : ${error}`);
return null;
}
};

const AccountQueries = {
getAccountListByPageAndParams,
getAccountDetailsByParams,
loginAccount,
};

export default AccountQueries;
13 changes: 13 additions & 0 deletions src/v6y-bff/src/resolvers/account/AccountResolvers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import AccountMutations from './AccountMutations.ts';
import AccountQueries from './AccountQueries.ts';

const AccountResolvers = {
Query: {
...AccountQueries,
},
Mutation: {
...AccountMutations,
},
};

export default AccountResolvers;
32 changes: 32 additions & 0 deletions src/v6y-bff/src/resolvers/manager/AuthenticationManager.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { ApolloServer } from '@apollo/server';
import { expressMiddleware } from '@apollo/server/express4';
import { passportAuthenticate } from '@v6y/commons';
import BodyParser from 'body-parser';
import Cors from 'cors';
import { RequestHandler } from 'express';

export function buildUserMiddleware(
server: ApolloServer,
apiPath: string,
): [string, RequestHandler, RequestHandler, RequestHandler] {
return [
apiPath as string,
Cors(),
BodyParser.json(),
expressMiddleware(server, {
context: async ({ req }) => {
if (
req.body?.operationName !== 'LoginAccount' &&
req.body?.operationName !== 'IntrospectionQuery'
) {
const user = await passportAuthenticate(req);
if (!user) {
throw new Error('Unauthorized');
}
return { user };
}
return {};
},
}),
];
}
Loading

0 comments on commit cbd51fd

Please sign in to comment.