Skip to content
This repository was archived by the owner on May 11, 2026. It is now read-only.
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
17 changes: 13 additions & 4 deletions src/helpers/alias.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import db from './mysql';

const DEFAULT_ALIAS_EXPIRY_DAYS = 30;

const TYPES_EXECUTABLE_BY_ALIAS = [
const TYPES_EXECUTABLE_BY_ALIAS: readonly string[] = [
'follow',
'unfollow',
'subscribe',
Expand All @@ -14,9 +14,14 @@ const TYPES_EXECUTABLE_BY_ALIAS = [
'vote-string',
'proposal',
'update-proposal',
'delete-proposal',
'flag-proposal'
] as const;
];

const TYPES_EXECUTABLE_BY_STARKNET_ALIAS: readonly string[] = ['delete-proposal'];

function isStarknetAddress(address: string): boolean {
return /^0x[0-9a-fA-F]{64}$/.test(address);
}

export async function isExistingAlias(
address: string,
Expand All @@ -39,7 +44,11 @@ export async function verifyAlias(type: string, body: any): Promise<void> {

if (body.address === message.from) return;

if (!TYPES_EXECUTABLE_BY_ALIAS.includes(type as any)) {
const allowed =
TYPES_EXECUTABLE_BY_ALIAS.includes(type) ||
(isStarknetAddress(message.from) && TYPES_EXECUTABLE_BY_STARKNET_ALIAS.includes(type));

if (!allowed) {
return Promise.reject(`alias not allowed for the type: ${type}`);
}

Expand Down
38 changes: 38 additions & 0 deletions test/unit/helpers/alias.test.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
import { verifyAlias } from '../../../src/helpers/alias';
import db from '../../../src/helpers/mysql';

jest.mock('../../../src/helpers/mysql', () => ({
__esModule: true,
default: { queryAsync: jest.fn() }
}));

const mockedQueryAsync = db.queryAsync as jest.Mock;

describe('verifyAlias()', () => {
beforeEach(() => {
mockedQueryAsync.mockReset();
});

it('resolves when the sender is the creator', async () => {
const body = { address: '0xabc', data: { message: { from: '0xabc' } } };
await expect(verifyAlias('vote', body)).resolves.toBeUndefined();
Expand All @@ -15,4 +22,35 @@ describe('verifyAlias()', () => {
const body = { address: '0xaaa', data: { message: { from: '0xbbb' } } };
await expect(verifyAlias('settings', body)).rejects.toMatch('alias not allowed');
});

it('rejects delete-proposal when the author is an EVM address', async () => {
const body = {
address: '0x91FD2c8d24767db4Ece7069AA27832ffaf8590f3',
data: { message: { from: '0x91FD2c8d24767db4Ece7069AA27832ffaf8590f4' } }
};
await expect(verifyAlias('delete-proposal', body)).rejects.toMatch('alias not allowed');
});

it('resolves delete-proposal when the author is a Starknet address with a valid alias', async () => {
const body = {
address: '0x91FD2c8d24767db4Ece7069AA27832ffaf8590f3',
data: {
message: {
from: '0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef'
}
}
};
mockedQueryAsync.mockResolvedValueOnce([{ 1: 1 }]);
await expect(verifyAlias('delete-proposal', body)).resolves.toBeUndefined();
expect(mockedQueryAsync).toHaveBeenCalledTimes(1);
});

it("rejects with 'wrong alias' when the type is allowed but no alias row exists", async () => {
const body = {
address: '0x91FD2c8d24767db4Ece7069AA27832ffaf8590f3',
data: { message: { from: '0x91FD2c8d24767db4Ece7069AA27832ffaf8590f4' } }
};
mockedQueryAsync.mockResolvedValueOnce([]);
await expect(verifyAlias('vote', body)).rejects.toMatch('wrong alias');
});
});
Loading