Skip to content

Commit

Permalink
Merge pull request #261 from shawakash/chat
Browse files Browse the repository at this point in the history
chore: enhanched the chat server by adding authentication
  • Loading branch information
shawakash authored Mar 18, 2024
2 parents 8392f21 + b6890be commit 03b019f
Show file tree
Hide file tree
Showing 25 changed files with 758 additions and 439 deletions.
80 changes: 3 additions & 77 deletions backend/api/src/Redis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,96 +5,22 @@ import { AddressCache } from "./redis/address";
import { TxnCache } from "./redis/txn";
import { WalletCache } from "./redis/wallet";
import { AccountCache } from "./redis/account";
import { RedisBase } from "@paybox/backend-common";

export class Redis {
private client: RedisClientType;
private static instance: Redis;
export class Redis extends RedisBase {
public clientCache: ClientCache;
public address: AddressCache;
public txn: TxnCache;
public wallet: WalletCache;
public account: AccountCache;

constructor() {
this.client = createClient({
url: REDIS_URL,
legacyMode: false,
socket: {
reconnectStrategy(retries, cause) {
if (retries > 20) {
console.log("Too many retries on REDIS. Connection Terminated");
return false;
} else {
console.log(`Retrying to connect to Redis ${PROCESS} server: ${cause}`);
return Math.min(retries * 100, 3000);
}
},
},

});

this.client.on('connect', () => {
console.log(`Redis ${PROCESS} server connect at port: ${REDIS_URL?.split(":").slice(-1)[0]}`);
});

this.client.on('error', (err) => {
console.error(`Error connecting to Redis ${PROCESS} server:`, err);
});



this.client.connect();
super();
this.clientCache = new ClientCache(this.client, this);
this.address = new AddressCache(this.client, this);
this.txn = new TxnCache(this.client, this);
this.wallet = new WalletCache(this.client, this);
this.account = new AccountCache(this.client, this);
}

public static getInstance(): Redis {
if (!this.instance) {
this.instance = new Redis();
}
return this.instance;
}

get getclient() {
return this.client;
}

async deleteHash(key: string) {
const deletedKeys = await this.client.del(key);
console.log(`Deleted hash with ${key} key`);
return deletedKeys;
}

async cacheIdUsingKey(key: string, item: string, expire?: number): Promise<void> {
await this.client.set(key, item, {
EX: expire,
});
console.log(`${item} is cached with ${key}`);
return;
}

async getIdFromKey(key: string): Promise<string | null> {
const id = await this.client.get(key);
if (!id) {
return null;
}
console.log(`Got id from key ${key}`);
return id;
}

// TODO: debounce here
async send(message: string) {
// await this.client.rPush(NOTIFICATIONS_QUEUE, message);
}

async publish(room: string, message: any) {
await this.client.publish(room, JSON.stringify(message));
}

async disconnect() {
await this.client.quit();
}
}
221 changes: 4 additions & 217 deletions backend/api/src/auth/middleware.ts
Original file line number Diff line number Diff line change
@@ -1,95 +1,26 @@
import { NextFunction, Request, Response } from "express";
import {
clearCookie,
getObjectFromR2,
setJWTCookie,
validateJwt,
validatePassword,

} from "./util";
import {
ADDRESS_CACHE_EXPIRE,
AccountGetPrivateKey,
AddressFormPartial,
GetQrQuerySchema,
Network,
PasswordValid,
QrcodeQuery,
TxnSendQuery,
VALID_CACHE_EXPIRE,
dbResStatus,
responseStatus,
} from "@paybox/common";
import { cache } from "..";
import { getAddressByClient } from "@paybox/backend-common";
import { Address } from "web3";
import { getPassword, queryValid } from "@paybox/backend-common";
import { EthOps } from "../sockets/eth";
import { SolOps } from "../sockets/sol";
import rateLimit from "express-rate-limit";
import {R2_QRCODE_BUCKET_NAME} from "../config";


/**
*
* @param req
* @param res
* @param next
* @returns id
*/
export const extractClientId = async (
req: Request,
res: Response,
next: NextFunction,
) => {
let jwt = "";

// Header takes precedence
const authHeader = req.headers["authorization"];
if (authHeader && authHeader.split(" ")[0] === "Bearer") {
jwt = authHeader.split(" ")[1];
} else if (req.cookies.jwt) {
jwt = req.cookies.jwt;
} else if (req.query.jwt) {
jwt = req.query.jwt as string;
}
import { R2_QRCODE_BUCKET_NAME } from "../config";

if (jwt) {
try {
const payloadRes = await validateJwt(jwt);
if (payloadRes.payload.sub) {
// Extend cookie or set it if not set
await setJWTCookie(req, res, payloadRes.payload.sub);
// Set id on request
//@ts-ignore
req.id = payloadRes.payload.sub;
// Set jwt on request
//@ts-ignore
req.jwt = jwt;
}
} catch {
clearCookie(res, "jwt");
return res
.status(403)
.json({ msg: "Auth error", status: responseStatus.Error });
}
} else {
return res.status(403).json({
msg: "No authentication token found",
status: responseStatus.Error,
});
}
next();
};

export const authMiddleware = (
req: Request,
res: Response,
next: NextFunction,
) => {
//@ts-ignore
req.authHeader = req.headers.authorization;
next();
};

/**
*
Expand Down Expand Up @@ -260,150 +191,6 @@ export const hasAddress = async (
}
};

/**
*
* @param req
* @param res
* @param next
* @returns
*/
export const checkPassword = async (
req: Request,
res: Response,
next: NextFunction,
) => {
try {
//@ts-ignore
const id = req.id;
if (id) {
const { password } = PasswordValid.parse(req.body);
// Password Check
const { status, hashPassword } = await getPassword(id);
if (status == dbResStatus.Error || hashPassword == undefined) {
return res
.status(503)
.json({ msg: "Database Error", status: responseStatus.Error });
}
const isCorrectPass = await validatePassword(password, hashPassword);
if (!isCorrectPass) {
return res
.status(401)
.json({ msg: "Wrong Password", status: responseStatus.Error });
}
} else {
return res
.status(500)
.json({ status: responseStatus.Error, msg: "Jwt error" });
}
next();
} catch (error) {
console.log(error);
return res.status(500).json({
status: responseStatus.Error,
msg: "Internal error",
error: error,
});
}
};

/**
*
* @param req
* @param res
* @param next
* @returns
*/
export const isValidated = async (
req: Request,
res: Response,
next: NextFunction
) => {
try {
//@ts-ignore
const id = req.id;
if (id) {

const validCache = await cache.getIdFromKey(`valid:${id}`);
if (validCache === 'true') {
return res
.status(200)
.json({ msg: "Client Phone Number is validated 😊", status: responseStatus.Ok });
}

const {status, valid} = await queryValid(id);
if (status == dbResStatus.Error) {
return res
.status(503)
.json({ msg: "Database Error", status: responseStatus.Error });
}
if (valid) {
return res
.status(200)
.json({ msg: "Client Phone Number is validated 😊", status: responseStatus.Ok });
}
} else {
return res
.status(500)
.json({ status: responseStatus.Error, msg: "Jwt error" });
}
next();
} catch (error) {
console.log(error);
return res.status(500).json({
status: responseStatus.Error,
msg: "Internal error",
error: error,
});
}
}

/**
*
* @param req
* @param res
* @param next
* @returns
*/
export const checkValidation = async (
req: Request,
res: Response,
next: NextFunction
) => {
try {
//@ts-ignore
const id = req.id;
if(id) {
const validCache = await cache.getIdFromKey(`valid:${id}`);
if (!validCache) {
//TODO: QUERY THE DB AND CACHE THE RESULT
const {status, valid} = await queryValid(id);
if (status == dbResStatus.Error) {
return res
.status(503)
.json({ msg: "Database Error", status: responseStatus.Error });
}
if (!valid) {
return res
.status(200)
.json({ msg: "Please verify your number or email first.", status: responseStatus.Error });
}
await cache.cacheIdUsingKey(`valid:${id}`, 'true', VALID_CACHE_EXPIRE);
}
} else {
return res
.status(500)
.json({ status: responseStatus.Error, msg: "Jwt error" });
}
next();
} catch (error) {
console.log(error);
return res.status(500).json({
status: responseStatus.Error,
msg: "Internal error",
error: error,
});
}
}

/**
*
Expand All @@ -420,8 +207,8 @@ export const checkQrcode = async (
try {
//@ts-ignore
const id = req.id;
if(id) {
const {accountId} = QrcodeQuery.parse(req.query);
if (id) {
const { accountId } = QrcodeQuery.parse(req.query);
const fileName = `qr:${accountId.slice(5)}`;
const body = await getObjectFromR2(R2_QRCODE_BUCKET_NAME, fileName);
if (body?.code) {
Expand Down
Loading

0 comments on commit 03b019f

Please sign in to comment.