Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

update multisig endpoints #19

Merged
merged 5 commits into from
Sep 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 0 additions & 7 deletions migrations/1694633909572-AddMultisigSessionEntity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,16 +56,9 @@ export class AddMultisigSessionEntity1694633909572
},
],
indices: [
{
columnNames: ['safeTransactionHash', 'network'],
isUnique: true,
},
{
columnNames: ['multisigAddress'],
},
{
columnNames: ['safeTransactionHash'],
},
{
columnNames: ['network'],
},
Expand Down
89 changes: 89 additions & 0 deletions migrations/1695476070385-UpdateMultisigSessionEntity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { MultisigStatuses } from '@/src/entities/multisigSession';

Check warning on line 1 in migrations/1695476070385-UpdateMultisigSessionEntity.ts

View workflow job for this annotation

GitHub Actions / test

'MultisigStatuses' is defined but never used

Check warning on line 1 in migrations/1695476070385-UpdateMultisigSessionEntity.ts

View workflow job for this annotation

GitHub Actions / test

'MultisigStatuses' is defined but never used
import {
MigrationInterface,
QueryRunner,
TableColumn,
TableIndex,
} from 'typeorm';

export class UpdateMultisigSessionEntity1695476070385
implements MigrationInterface
{
public async up(queryRunner: QueryRunner): Promise<void> {
const table = await queryRunner.getTable('multisig_session');
if (!table) return;

// Adding new columns
const statusColumnExists = table.columns.some(c => c.name === 'status');
if (!statusColumnExists) {
await queryRunner.addColumn(
'multisig_session',
new TableColumn({
name: 'status',
type: 'varchar',
isNullable: true,
}),
);
}

// Renaming column safeTransactionMessage to safeMessageHash
const safeTransactionMessageColumnExists = table.columns.some(
c => c.name === 'safeTransactionMessage',
);
if (safeTransactionMessageColumnExists) {
await queryRunner.renameColumn(
'multisig_session',
'safeTransactionMessage',
'safeMessageHash',
);
}

// Creating indices for safeMessageHash
const safeMessageHashIndexExists = table.indices.some(
idx => idx.columnNames.indexOf('safeMessageHash') !== -1,
);
if (!safeMessageHashIndexExists) {
await queryRunner.createIndex(
'multisig_session',
new TableIndex({
name: 'IDX_MULTISIG_SAFE_MESSAGE_HASH',
columnNames: ['safeMessageHash'],
}),
);
}
}

public async down(queryRunner: QueryRunner): Promise<void> {
const table = await queryRunner.getTable('multisig_session');
if (!table) return;

// Dropping indices for messageHash and safeMessageHash
const safeMessageHashIndexExists = table.indices.some(
idx => idx.columnNames.indexOf('safeMessageHash') !== -1,
);
if (safeMessageHashIndexExists) {
await queryRunner.dropIndex(
'multisig_session',
'IDX_MULTISIG_SAFE_MESSAGE_HASH',
);
}

// Renaming column back to safeTransactionMessage
const safeMessageHashColumnExists = table.columns.some(
c => c.name === 'safeMessageHash',
);
if (safeMessageHashColumnExists) {
await queryRunner.renameColumn(
'multisig_session',
'safeMessageHash',
'safeTransactionMessage',
);
}

// Dropping the added columns
const statusColumnExists = table.columns.some(c => c.name === 'status');
if (statusColumnExists) {
await queryRunner.dropColumn('multisig_session', 'status');
}
}
}
113 changes: 60 additions & 53 deletions src/controllers/v1/multisigAuthenticationController.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,27 @@
import { SiweMessage } from 'siwe';
import { Route, Tags, Post, Body } from 'tsoa';
import SafeApiKit from '@safe-global/api-kit';
import {
AuthenticationRequest,
AuthenticationResponse,
MultisigAuthenticationRequest,
MultisigAuthenticationResponse,
} from '../../types/requestResponses';
import { StandardError } from '../../types/StandardError';
import { errorMessagesEnum } from '../../utils/errorMessages';
import { logger } from '../../utils/logger';
import { generateAccessToken } from '@/src/services/authenticationService';
import {
findNonExpiredMultisigSessions,
firstOrCreateMultisigSession,

Check warning on line 12 in src/controllers/v1/multisigAuthenticationController.ts

View workflow job for this annotation

GitHub Actions / test

'firstOrCreateMultisigSession' is defined but never used

Check warning on line 12 in src/controllers/v1/multisigAuthenticationController.ts

View workflow job for this annotation

GitHub Actions / test

'firstOrCreateMultisigSession' is defined but never used
} from '@/src/repositories/multisigSessionRepository';
import {
fetchSafeMessage,
fetchSafeMessageByTimestamp,
getSafeApiKit,
} from '@/src/services/safeServices';
import { validateJwt } from '@/src/services/jwtService';
import {
getProvider,
getSafeTransactionNetworkUrl,
} from '@/src/utils/provider';
import { EthersAdapter } from '@safe-global/protocol-kit';
import { ethers } from 'ethers';
import { MultisigSession } from '@/src/entities/multisigSession';
MultisigSession,
MultisigStatuses,
} from '@/src/entities/multisigSession';
import moment from 'moment';
import { generateAccessToken } from '@/src/services/authenticationService';
import { verify } from 'jsonwebtoken';
import { findAccessTokenByUniqueIdentifiers } from '@/src/repositories/accessTokenRepository';
import { firstOrCreateMultisigSession } from '@/src/repositories/multisigSessionRepository';

@Route('/v1/multisigAuthentication')
@Tags('Authentication')
Expand All @@ -31,62 +31,69 @@
@Body() body: MultisigAuthenticationRequest,
): Promise<MultisigAuthenticationResponse> {
try {
let token: any;

Check warning on line 34 in src/controllers/v1/multisigAuthenticationController.ts

View workflow job for this annotation

GitHub Actions / test

Unexpected any. Specify a different type
const provider = getProvider(body.network);

const ethAdapter = new EthersAdapter({
ethers,
signerOrProvider: provider,
});
let multisigSession: any;

Check warning on line 35 in src/controllers/v1/multisigAuthenticationController.ts

View workflow job for this annotation

GitHub Actions / test

Unexpected any. Specify a different type
let safeMessage: any;

Check warning on line 36 in src/controllers/v1/multisigAuthenticationController.ts

View workflow job for this annotation

GitHub Actions / test

Unexpected any. Specify a different type
const safeService = await getSafeApiKit(body.network);
const verifiedJwt = await validateJwt(body.jwt);

const safeService = new SafeApiKit({
txServiceUrl: getSafeTransactionNetworkUrl(body.network),
ethAdapter,
});
const safeMultisigTransactionResponse = await safeService.getTransaction(
body.transactionHash,
);

const safeAddress = safeMultisigTransactionResponse.safe;
const safeInfo = await safeService.getSafeInfo(safeAddress);

const multisigSession = await firstOrCreateMultisigSession(
body.transactionHash,
body.message,
safeAddress,
multisigSession = await findNonExpiredMultisigSessions(
body.safeAddress,
body.network,
);

const verifiedJwt = verify(
body.jwt,
process.env.JWT_SECRET as string,
) as any;
if (!multisigSession && body.safeMessageTimestamp) {
safeMessage = await fetchSafeMessageByTimestamp(
body.safeAddress,
body.safeMessageTimestamp,
body.network,
);
} else if (multisigSession && !body.safeMessageTimestamp) {
safeMessage = await fetchSafeMessage(
multisigSession.safeMessageHash,
body.network,
);
} else {
throw new StandardError(errorMessagesEnum.MULTISIG_INVALID_REQUEST);
}

const dbAccessToken = await findAccessTokenByUniqueIdentifiers(
body.jwt,
verifiedJwt.jti,
);
if (!safeMessage)
throw new StandardError(errorMessagesEnum.MULTISIG_MESSAGE_NOT_FOUND);

const safeInfo = await safeService.getSafeInfo(body.safeAddress);

if (!dbAccessToken)
throw new StandardError(errorMessagesEnum.JWT_NOT_FOUND);
if (
!multisigSession &&
safeMessage?.proposedBy?.value !== verifiedJwt.publicAddress
)
throw new StandardError(errorMessagesEnum.NOT_SAFE_OWNER);

if (!safeInfo.owners.includes(verifiedJwt.publicAddress))
throw new StandardError(errorMessagesEnum.NOT_SAFE_OWNER);

if (safeMultisigTransactionResponse.isSuccessful) {
token = await generateAccessToken({ address: safeAddress });
logger.info(
`Multisig with address ${multisigSession.multisigAddress} logged in`,
);
if (!multisigSession) {
multisigSession = MultisigSession.create({
expirationDate: moment().add(1, 'week').toDate(),
safeMessageHash: safeMessage.messageHash,
multisigAddress: body.safeAddress,
network: body.network,
active: true,
});
}

if (
(await multisigSession.multisigStatus(safeMessage)) ===
MultisigStatuses.Successful
) {
token = await generateAccessToken({ address: safeMessage.safe });
logger.info(`Multisig with address ${safeMessage.safe} logged in`);
}

return {
jwt: token?.jwt,
expiration: multisigSession.expirationDate.valueOf(),
publicAddress: multisigSession.multisigAddress,
status: multisigSession.multisigStatus(
safeMultisigTransactionResponse?.isSuccessful,
),
status: multisigSession.status,
};
} catch (e) {
logger.error('multisigAuthenticationController error', e);
Expand Down
100 changes: 0 additions & 100 deletions src/controllers/v1/multisigAuthorizationController.ts

This file was deleted.

Loading
Loading