Skip to content

Commit

Permalink
Pro 2455 Access restrictions safe mode (#112)
Browse files Browse the repository at this point in the history
* feat: PRO-2455 auth restrictions for admin ops

* fix: PRO-2455 apiKey validation for enable, disable and delete policy

* fix: PRO-2455 upgrade the package versions
  • Loading branch information
kanthgithub authored Jun 28, 2024
1 parent 2d265c8 commit 0c37e7c
Show file tree
Hide file tree
Showing 9 changed files with 139 additions and 278 deletions.
2 changes: 1 addition & 1 deletion admin_frontend/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "admin_frontend",
"version": "1.2.7",
"version": "1.2.8",
"private": true,
"dependencies": {
"@emotion/react": "11.11.3",
Expand Down
2 changes: 1 addition & 1 deletion backend/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "arka",
"version": "1.2.7",
"version": "1.2.8",
"description": "ARKA - (Albanian for Cashier's case) is the first open source Paymaster as a service software",
"type": "module",
"directories": {
Expand Down
7 changes: 5 additions & 2 deletions backend/src/constants/ErrorMessage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ export default {
UNSUPPORTED_NETWORK: 'Unsupported network',
UNSUPPORTED_NETWORK_TOKEN: 'Unsupported network/token',
EMPTY_BODY: 'Empty Body received',
API_KEY_IS_REQUIRED_IN_HEADER: 'Api Key is required in header',
API_KEY_DOES_NOT_EXIST_FOR_THE_WALLET_ADDRESS: 'Api Key does not exist for the wallet address',
WALLET_ADDRESS_DOES_NOT_MATCH_FOR_THE_API_KEY: 'Wallet address does not match for the Api Key',
FAILED_TO_CREATE_SPONSORSHIP_POLICY: 'Failed to create sponsorship policy',
FAILED_TO_UPDATE_SPONSORSHIP_POLICY: 'Failed to update sponsorship policy',
SPONSORSHIP_POLICY_CHAINS_NOT_IN_SUBSET_OF_APIKEY_SUPPORTED_CHAINS: 'Sponsorship policy chains: {sponsorshipPolicyChains} are not in subset of ApiKey supported networks {apiKeyChains}',
Expand All @@ -16,8 +18,8 @@ export default {
NO_ACTIVE_SPONSORSHIP_POLICY_FOR_CURRENT_TIME: 'No active sponsorship policy for wallet address {walletAddress} with EP version {epVersion} and ChainId: ${chainId}',
SPONSORSHIP_POLICY_IS_DISABLED: 'Sponsorship policy is disabled',
FAILED_TO_DELETE_SPONSORSHIP_POLICY: 'Failed to delete sponsorship policy',
FAILED_TO_ENABLE_SPONSORSHIP_POLICY: 'Failed to enable sponsorship policy',
FAILED_TO_DISABLE_SPONSORSHIP_POLICY: 'Failed to disable sponsorship policy',
FAILED_TO_ENABLE_SPONSORSHIP_POLICY: 'Failed to enable sponsorship policy - {error}',
FAILED_TO_DISABLE_SPONSORSHIP_POLICY: 'Failed to disable sponsorship policy - {error}',
FAILED_TO_QUERY_SPONSORSHIP_POLICY: 'Failed to query sponsorship policy',
FAILED_TO_PROCESS: 'Failed to process the request. Please try again or contact ARKA support team',
INVALID_MODE: 'Invalid mode selected',
Expand All @@ -26,6 +28,7 @@ export default {
RPC_ERROR: 'rpcError while checking whitelist. Please try again later',
QUOTA_EXCEEDED: 'Quota exceeded for this month',
INVALID_USER: 'Unauthorised User',
NOT_AUTHORIZED: 'Not authorized to perform this action',
RECORD_NOT_FOUND: 'Api Key provided not found',
API_KEY_VALIDATION_FAILED: 'Api Key is not in the right format as described in readme file',
UNSUPPORTED_METHOD: 'Unsupported method name received',
Expand Down
2 changes: 2 additions & 0 deletions backend/src/constants/ReturnCode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,6 @@ export default {
FAILURE: 400,
BAD_REQUEST: 400,
NOT_FOUND: 404,
INTERNAL_SERVER_ERROR: 500,
NOT_AUTHORIZED: 403,
}
2 changes: 2 additions & 0 deletions backend/src/plugins/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ const ConfigSchema = Type.Strict(
DATABASE_SSL_ENABLED: Type.Boolean() || undefined,
DATABASE_SCHEMA_NAME: Type.String() || undefined,
HMAC_SECRET: Type.String({ minLength: 1 }),
UNSAFE_MODE: Type.Boolean() || undefined,
})
);

Expand Down Expand Up @@ -62,6 +63,7 @@ const configPlugin: FastifyPluginAsync = async (server) => {
DATABASE_SSL_ENABLED: process.env.DATABASE_SSL_ENABLED === 'true',
DATABASE_SCHEMA_NAME: process.env.DATABASE_SCHEMA_NAME ?? 'arka',
HMAC_SECRET: process.env.HMAC_SECRET ?? '',
UNSAFE_MODE: process.env.UNSAFE_MODE === 'true',
}

server.decorate("config", config);
Expand Down
16 changes: 10 additions & 6 deletions backend/src/repository/sponsorship-policy-repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Sequelize, Op } from 'sequelize';
import { SponsorshipPolicy } from '../models/sponsorship-policy.js';
import { EPVersions, SponsorshipPolicyDto, getEPVersionString } from '../types/sponsorship-policy-dto.js';
import { ethers } from 'ethers';
import { server } from 'server.js';

export class SponsorshipPolicyRepository {
private sequelize: Sequelize;
Expand Down Expand Up @@ -394,8 +395,12 @@ export class SponsorshipPolicyRepository {
existingSponsorshipPolicy.name = sponsorshipPolicy.name;
existingSponsorshipPolicy.description = sponsorshipPolicy.description;
existingSponsorshipPolicy.isApplicableToAllNetworks = sponsorshipPolicy.isApplicableToAllNetworks;
if (sponsorshipPolicy.isApplicableToAllNetworks && sponsorshipPolicy.enabledChains) {
existingSponsorshipPolicy.enabledChains = undefined;
} else {
existingSponsorshipPolicy.enabledChains = sponsorshipPolicy.enabledChains;
}
existingSponsorshipPolicy.isPerpetual = sponsorshipPolicy.isPerpetual;
existingSponsorshipPolicy.supportedEPVersions = sponsorshipPolicy.supportedEPVersions;

// if marked as IsPerpetual, then set startTime and endTime to null
if (sponsorshipPolicy.isPerpetual) {
Expand All @@ -416,6 +421,8 @@ export class SponsorshipPolicyRepository {
}
}

existingSponsorshipPolicy.supportedEPVersions = sponsorshipPolicy.supportedEPVersions;

existingSponsorshipPolicy.globalMaximumApplicable = sponsorshipPolicy.globalMaximumApplicable;

if (existingSponsorshipPolicy.globalMaximumApplicable) {
Expand Down Expand Up @@ -501,16 +508,13 @@ export class SponsorshipPolicyRepository {
existingSponsorshipPolicy.addressBlockList = null;
}

// const result = await existingSponsorshipPolicy.save();
// return result.get() as SponsorshipPolicy;

// apply same logic to update the record
const result = await this.sequelize.models.SponsorshipPolicy.update({
name: existingSponsorshipPolicy.name,
description: existingSponsorshipPolicy.description,
isApplicableToAllNetworks: existingSponsorshipPolicy.isApplicableToAllNetworks,
enabledChains: existingSponsorshipPolicy.enabledChains,
supportedEPVersions: existingSponsorshipPolicy.supportedEPVersions,
enabledChains: existingSponsorshipPolicy.enabledChains && existingSponsorshipPolicy.enabledChains.length >= 0 ? existingSponsorshipPolicy.enabledChains : null,
supportedEPVersions: existingSponsorshipPolicy.supportedEPVersions && existingSponsorshipPolicy.supportedEPVersions.length >= 0 ? existingSponsorshipPolicy.supportedEPVersions : null,
isPerpetual: existingSponsorshipPolicy.isPerpetual,
startTime: existingSponsorshipPolicy.startTime,
endTime: existingSponsorshipPolicy.endTime,
Expand Down
21 changes: 21 additions & 0 deletions backend/src/routes/admin-routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ import { ApiKeyDto } from "../types/apikey-dto.js";
const adminRoutes: FastifyPluginAsync = async (server) => {
server.post('/adminLogin', async function (request, reply) {
try {
if(!server.config.UNSAFE_MODE) {
return reply.code(ReturnCode.NOT_AUTHORIZED).send({ error: ErrorMessage.NOT_AUTHORIZED });
}
const body: any = JSON.parse(request.body as string);
if (!body) return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.EMPTY_BODY });
if (!body.walletAddress) return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.INVALID_DATA });
Expand All @@ -25,6 +28,9 @@ const adminRoutes: FastifyPluginAsync = async (server) => {

server.get("/getConfig", async function (request, reply) {
try {
if(!server.config.UNSAFE_MODE) {
return reply.code(ReturnCode.NOT_AUTHORIZED).send({ error: ErrorMessage.NOT_AUTHORIZED });
}
const result = await server.arkaConfigRepository.findFirstConfig();

if (!result) {
Expand All @@ -40,6 +46,9 @@ const adminRoutes: FastifyPluginAsync = async (server) => {

server.post("/saveConfig", async function (request, reply) {
try {
if(!server.config.UNSAFE_MODE) {
return reply.code(ReturnCode.NOT_AUTHORIZED).send({ error: ErrorMessage.NOT_AUTHORIZED });
}
const body: ArkaConfigUpdateData = JSON.parse(request.body as string);
if (!body) return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.EMPTY_BODY });
if (Object.values(body).every(value => value)) {
Expand Down Expand Up @@ -67,6 +76,9 @@ const adminRoutes: FastifyPluginAsync = async (server) => {

server.post('/saveKey', async function (request, reply) {
try {
if(!server.config.UNSAFE_MODE) {
return reply.code(ReturnCode.NOT_AUTHORIZED).send({ error: ErrorMessage.NOT_AUTHORIZED });
}
const body: any = JSON.parse(request.body as string) as ApiKeyDto;
if (!body) return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.EMPTY_BODY });
if (!body.apiKey || !body.privateKey)
Expand Down Expand Up @@ -110,6 +122,9 @@ const adminRoutes: FastifyPluginAsync = async (server) => {

server.post('/updateKey', async function (request, reply) {
try {
if(!server.config.UNSAFE_MODE) {
return reply.code(ReturnCode.NOT_AUTHORIZED).send({ error: ErrorMessage.NOT_AUTHORIZED });
}
const body = JSON.parse(request.body as string) as ApiKeyDto;
if (!body) return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.EMPTY_BODY });
if (!body.apiKey)
Expand Down Expand Up @@ -138,6 +153,9 @@ const adminRoutes: FastifyPluginAsync = async (server) => {

server.get('/getKeys', async function (request, reply) {
try {
if(!server.config.UNSAFE_MODE) {
return reply.code(ReturnCode.NOT_AUTHORIZED).send({ error: ErrorMessage.NOT_AUTHORIZED });
}
if (!server.sequelize) throw new Error('Sequelize instance is not available');

const apiKeys = await server.apiKeyRepository.findAll();
Expand All @@ -153,6 +171,9 @@ const adminRoutes: FastifyPluginAsync = async (server) => {

server.post('/deleteKey', async function (request, reply) {
try {
if(!server.config.UNSAFE_MODE) {
return reply.code(ReturnCode.NOT_AUTHORIZED).send({ error: ErrorMessage.NOT_AUTHORIZED });
}
const body: any = JSON.parse(request.body as string);
if (!body) return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.EMPTY_BODY });
if (!body.apiKey)
Expand Down
Loading

0 comments on commit 0c37e7c

Please sign in to comment.