diff --git a/migrations/1696397559095-AddExpirationDateResetToMultisigSession.ts b/migrations/1696397559095-AddExpirationDateResetToMultisigSession.ts new file mode 100644 index 0000000..7184e2d --- /dev/null +++ b/migrations/1696397559095-AddExpirationDateResetToMultisigSession.ts @@ -0,0 +1,20 @@ +import { MigrationInterface, QueryRunner, TableColumn } from 'typeorm'; + +export class AddExpirationDateResetToMultisigSession1696397559095 + implements MigrationInterface +{ + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.addColumn( + 'multisig_session', + new TableColumn({ + name: 'approvalExpirationDate', + type: 'date', + isNullable: true, + }), + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.dropColumn('multisig_session', 'approvalExpirationDate'); + } +} diff --git a/src/controllers/v1/multisigAuthenticationController.ts b/src/controllers/v1/multisigAuthenticationController.ts index 40833a6..09c7978 100644 --- a/src/controllers/v1/multisigAuthenticationController.ts +++ b/src/controllers/v1/multisigAuthenticationController.ts @@ -42,6 +42,10 @@ export class MultisigAuthenticationController { body.network, ); + if (!multisigSession && !body.approvalExpirationDays) { + throw new StandardError(errorMessagesEnum.MULTISIG_INVALID_REQUEST); + } + if (!multisigSession && body.safeMessageTimestamp) { safeMessage = await fetchSafeMessageByTimestamp( body.safeAddress, @@ -73,6 +77,9 @@ export class MultisigAuthenticationController { if (!multisigSession) { multisigSession = MultisigSession.create({ + approvalExpirationDate: moment() + .add(body.approvalExpirationDays, 'days') + .toDate(), expirationDate: moment().add(1, 'week').toDate(), safeMessageHash: safeMessage.messageHash, multisigAddress: body.safeAddress, @@ -85,7 +92,19 @@ export class MultisigAuthenticationController { (await multisigSession.multisigStatus(safeMessage)) === MultisigStatuses.Successful ) { - token = await generateAccessToken({ address: body.safeAddress }); + if ( + multisigSession.expirationDate !== + multisigSession.approvalExpirationDAte + ) { + multisigSession.expirationDate = + multisigSession.approvalExpirationDate; + await multisigSession.save(); + } + + token = await generateAccessToken({ + address: body.safeAddress, + expirationDate: multisigSession.expirationDate, + }); logger.info(`Multisig with address ${body.safeAddress} logged in`); } diff --git a/src/entities/multisigSession.ts b/src/entities/multisigSession.ts index d068f9d..88d2e62 100644 --- a/src/entities/multisigSession.ts +++ b/src/entities/multisigSession.ts @@ -45,6 +45,9 @@ export class MultisigSession extends BaseEntity { @Column({ nullable: false }) expirationDate: Date; + @Column({ nullable: true }) + approvalExpirationDate: Date; + didExpire(): boolean { return this.expirationDate.valueOf() < moment().valueOf(); } diff --git a/src/routes/v1/multisigAuthenticationRouter.ts b/src/routes/v1/multisigAuthenticationRouter.ts index a5ea8a0..c2c217c 100644 --- a/src/routes/v1/multisigAuthenticationRouter.ts +++ b/src/routes/v1/multisigAuthenticationRouter.ts @@ -11,12 +11,14 @@ multisigAuthenticationRouter.post( try { const { safeAddress, network, jwt } = req.body; const safeMessageTimestamp = req.body?.safeMessageTimestamp; + const approvalExpirationDays = req.body?.approvalExpirationDays; if (!safeAddress || !jwt || !network) { res.status(422).json({ message: errorMessagesEnum.MISSING_LOGIN_DATA }); return; } const result = await multisigAuthenticationController.authenticate({ + approvalExpirationDays, safeMessageTimestamp, safeAddress, network, diff --git a/src/services/authenticationService.ts b/src/services/authenticationService.ts index 8036757..82c9b07 100644 --- a/src/services/authenticationService.ts +++ b/src/services/authenticationService.ts @@ -5,6 +5,7 @@ import { generateJwt, JwtPayload } from './jwtService'; interface AccessTokenFields { address: string; + expirationDate?: Date; } export const generateAccessToken = async ( @@ -12,12 +13,17 @@ export const generateAccessToken = async ( isPassport = false, ): Promise => { const jti = `${new Date().getTime()}-${generateRandomString(5)}`; + let expirationDate: Date; - const expirationDate = moment().add(30, 'days'); + if (fields.expirationDate) { + expirationDate = fields.expirationDate; + } else { + expirationDate = moment().add(30, 'days').toDate(); + } const jwtPayload: JwtPayload = { publicAddress: fields.address, - expirationDate: expirationDate.toDate(), + expirationDate: expirationDate, jti: jti, }; if (isPassport) { diff --git a/src/types/requestResponses.ts b/src/types/requestResponses.ts index cb0d101..c5c8892 100644 --- a/src/types/requestResponses.ts +++ b/src/types/requestResponses.ts @@ -8,6 +8,7 @@ export type AuthenticationRequest = { export type MultisigAuthenticationRequest = { safeMessageTimestamp?: number; + approvalExpirationDays?: number; safeAddress: string; network: number; jwt: string;