add: add auth session
This commit is contained in:
parent
bfae676c2e
commit
9b08ee4fed
7 changed files with 164 additions and 0 deletions
|
|
@ -1 +1,3 @@
|
||||||
export const NON_NEGATIVE_REAL_NUMBER_REGEX = /^\d+(\.\d+)?$/;
|
export const NON_NEGATIVE_REAL_NUMBER_REGEX = /^\d+(\.\d+)?$/;
|
||||||
|
|
||||||
|
export const AUTH_MESSAGE_EXPIRATION_TIME_MS = 5 * 60 * 1000; // 5 minutes
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,38 @@
|
||||||
import jwt from 'jsonwebtoken';
|
import jwt from 'jsonwebtoken';
|
||||||
import dotenv from 'dotenv';
|
import dotenv from 'dotenv';
|
||||||
import { Request, Response } from 'express';
|
import { Request, Response } from 'express';
|
||||||
|
import crypto from 'crypto';
|
||||||
|
|
||||||
import AuthData from '@/interfaces/bodies/user/AuthData.js';
|
import AuthData from '@/interfaces/bodies/user/AuthData.js';
|
||||||
|
import RequestAuthBody from '@/interfaces/bodies/auth/RequestAuthBody.js';
|
||||||
|
import authMessagesModel from '@/models/AuthMessages.js';
|
||||||
|
import { AUTH_MESSAGE_EXPIRATION_TIME_MS } from 'shared/constants.js';
|
||||||
|
import RequestAuthRes from '@/interfaces/responses/auth/RequestAuthRes.js';
|
||||||
import validateWallet from '../methods/validateWallet.js';
|
import validateWallet from '../methods/validateWallet.js';
|
||||||
import userModel from '../models/User.js';
|
import userModel from '../models/User.js';
|
||||||
|
|
||||||
dotenv.config();
|
dotenv.config();
|
||||||
|
|
||||||
class AuthController {
|
class AuthController {
|
||||||
|
requestAuth = async (req: Request, res: Response<RequestAuthRes>) => {
|
||||||
|
const { address, alias } = req.body as RequestAuthBody;
|
||||||
|
|
||||||
|
const message = crypto.randomUUID();
|
||||||
|
const expiresAt = new Date(Date.now() + AUTH_MESSAGE_EXPIRATION_TIME_MS);
|
||||||
|
|
||||||
|
const authMessageRow = await authMessagesModel.create({
|
||||||
|
address,
|
||||||
|
alias,
|
||||||
|
message,
|
||||||
|
expiresAt,
|
||||||
|
});
|
||||||
|
|
||||||
|
return res.status(200).send({
|
||||||
|
success: true,
|
||||||
|
data: authMessageRow.message,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
async auth(req: Request, res: Response) {
|
async auth(req: Request, res: Response) {
|
||||||
try {
|
try {
|
||||||
const userData: AuthData = req.body.data;
|
const userData: AuthData = req.body.data;
|
||||||
|
|
@ -18,6 +43,16 @@ class AuthController {
|
||||||
return res.status(400).send({ success: false, data: 'Invalid auth data' });
|
return res.status(400).send({ success: false, data: 'Invalid auth data' });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const authMessageRow = await authMessagesModel.findOne({
|
||||||
|
address,
|
||||||
|
alias,
|
||||||
|
message,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!authMessageRow) {
|
||||||
|
return res.status(400).send({ success: false, data: 'Invalid auth message' });
|
||||||
|
}
|
||||||
|
|
||||||
const dataValid = !!(
|
const dataValid = !!(
|
||||||
userData &&
|
userData &&
|
||||||
userData.address &&
|
userData.address &&
|
||||||
|
|
|
||||||
13
src/interfaces/bodies/auth/RequestAuthBody.ts
Normal file
13
src/interfaces/bodies/auth/RequestAuthBody.ts
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
import { body } from 'express-validator';
|
||||||
|
|
||||||
|
interface RequestAuthBody {
|
||||||
|
address: string;
|
||||||
|
alias: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const requestAuthBodyValidator = [
|
||||||
|
body('address').isString().notEmpty(),
|
||||||
|
body('alias').isString().notEmpty(),
|
||||||
|
];
|
||||||
|
|
||||||
|
export default RequestAuthBody;
|
||||||
7
src/interfaces/responses/auth/RequestAuthRes.ts
Normal file
7
src/interfaces/responses/auth/RequestAuthRes.ts
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
interface RequestAuthRes {
|
||||||
|
success: true;
|
||||||
|
// Auth message
|
||||||
|
data: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default RequestAuthRes;
|
||||||
53
src/models/AuthMessages.ts
Normal file
53
src/models/AuthMessages.ts
Normal file
|
|
@ -0,0 +1,53 @@
|
||||||
|
import { Transaction } from 'sequelize';
|
||||||
|
|
||||||
|
import AuthMessage from '@/schemes/AuthMessage';
|
||||||
|
|
||||||
|
class AuthMessagesModel {
|
||||||
|
create = async (
|
||||||
|
{
|
||||||
|
address,
|
||||||
|
alias,
|
||||||
|
message,
|
||||||
|
expiresAt,
|
||||||
|
}: {
|
||||||
|
address: string;
|
||||||
|
alias: string;
|
||||||
|
message: string;
|
||||||
|
expiresAt: Date;
|
||||||
|
},
|
||||||
|
{ transaction }: { transaction?: Transaction } = {},
|
||||||
|
): Promise<AuthMessage> => {
|
||||||
|
const authMessage = await AuthMessage.create(
|
||||||
|
{
|
||||||
|
address,
|
||||||
|
alias,
|
||||||
|
message,
|
||||||
|
expiresAt,
|
||||||
|
},
|
||||||
|
{ transaction },
|
||||||
|
);
|
||||||
|
|
||||||
|
return authMessage;
|
||||||
|
};
|
||||||
|
|
||||||
|
findOne = async ({
|
||||||
|
address,
|
||||||
|
alias,
|
||||||
|
message,
|
||||||
|
}: {
|
||||||
|
address: string;
|
||||||
|
alias: string;
|
||||||
|
message: string;
|
||||||
|
}): Promise<AuthMessage | null> =>
|
||||||
|
AuthMessage.findOne({
|
||||||
|
where: {
|
||||||
|
address,
|
||||||
|
alias,
|
||||||
|
message,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const authMessagesModel = new AuthMessagesModel();
|
||||||
|
|
||||||
|
export default authMessagesModel;
|
||||||
|
|
@ -1,8 +1,16 @@
|
||||||
import express from 'express';
|
import express from 'express';
|
||||||
|
|
||||||
|
import middleware from '@/middleware/middleware.js';
|
||||||
|
import { requestAuthBodyValidator } from '@/interfaces/bodies/auth/RequestAuthBody.js';
|
||||||
import authController from '../controllers/auth.controller.js';
|
import authController from '../controllers/auth.controller.js';
|
||||||
|
|
||||||
const authRouter = express.Router();
|
const authRouter = express.Router();
|
||||||
|
|
||||||
|
authRouter.post(
|
||||||
|
'/request-auth',
|
||||||
|
middleware.expressValidator(requestAuthBodyValidator),
|
||||||
|
authController.requestAuth.bind(authController),
|
||||||
|
);
|
||||||
authRouter.post('/auth', authController.auth);
|
authRouter.post('/auth', authController.auth);
|
||||||
|
|
||||||
export default authRouter;
|
export default authRouter;
|
||||||
|
|
|
||||||
46
src/schemes/AuthMessage.ts
Normal file
46
src/schemes/AuthMessage.ts
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
import sequelize from '@/sequelize';
|
||||||
|
import { DataTypes, Model } from 'sequelize';
|
||||||
|
|
||||||
|
class AuthMessage extends Model {
|
||||||
|
declare readonly id: number;
|
||||||
|
declare address: string;
|
||||||
|
declare alias: string;
|
||||||
|
declare message: string;
|
||||||
|
declare expiresAt: Date;
|
||||||
|
|
||||||
|
declare readonly createdAt: Date;
|
||||||
|
declare readonly updatedAt: Date;
|
||||||
|
}
|
||||||
|
|
||||||
|
AuthMessage.init(
|
||||||
|
{
|
||||||
|
id: {
|
||||||
|
type: DataTypes.INTEGER,
|
||||||
|
primaryKey: true,
|
||||||
|
autoIncrement: true,
|
||||||
|
},
|
||||||
|
address: {
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
allowNull: false,
|
||||||
|
},
|
||||||
|
alias: {
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
allowNull: false,
|
||||||
|
},
|
||||||
|
message: {
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
allowNull: false,
|
||||||
|
},
|
||||||
|
expiresAt: {
|
||||||
|
type: DataTypes.DATE,
|
||||||
|
allowNull: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
sequelize,
|
||||||
|
modelName: 'AuthMessage',
|
||||||
|
tableName: 'auth_messages',
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
export default AuthMessage;
|
||||||
Loading…
Add table
Reference in a new issue