Skip to content
Open
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
36 changes: 5 additions & 31 deletions src/components/Auth/LoginForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { Input } from '@nextui-org/input';
import React, { useState } from 'react';
import { useForm } from 'react-hook-form';
import { TFA_CODE_RULES } from '@/global/validationRules';
import { ChallengeMessage, IAuthResponse, TokenType, Wallet } from '@/global/types';
import { IAuthResponse, TokenType, Wallet } from '@/global/types';
import nextApiClientFetch from '@/utils/nextApiClientFetch';
import { handleTokenChange } from '@/services/auth.service';
import { useApiContext, useUserDetailsContext } from '@/contexts';
Expand All @@ -20,6 +20,7 @@ import APP_NAME from '@/global/constants/appName';
import getSubstrateAddress from '@/utils/getSubstrateAddress';
import { stringToHex } from '@polkadot/util';
import { SignerResult } from '@polkadot/api/types';
import { SIGN_MESSAGE } from '@/global/constants/signMessage';
import WalletButtonsRow from './WalletButtonsRow';
import AlertCard from '../Misc/AlertCard';
import AddressDropdown from './AddressDropdown';
Expand Down Expand Up @@ -90,27 +91,15 @@ function LoginForm({ onClose }: { onClose?: () => void }) {
try {
setLoading(true);

const { data: signupStartData, error: signupStartError } = await nextApiClientFetch<ChallengeMessage>({
network,
url: 'api/v1/auth/actions/addressSignupStart',
isPolkassemblyAPI: true,
data: { address: substrateAddress }
});

if (signupStartError || !signupStartData) throw new Error(signupStartError || 'Something went wrong');

const signupStartSignMessage = signupStartData?.signMessage;
if (!signupStartSignMessage) throw new Error('Signup challenge message not found.');

const { signature: signupSignature } = await signRaw({
address: substrateAddress,
data: stringToHex(signupStartSignMessage),
data: stringToHex(SIGN_MESSAGE),
type: 'bytes'
Comment on lines +96 to 97
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Security Issue: Using a Static Signing Message May Lead to Replay Attacks

Using a static SIGN_MESSAGE for authentication can expose the system to replay attacks. An attacker could capture the signature and reuse it to impersonate the user. It is recommended to use a unique, server-generated challenge message (nonce) for each authentication attempt to ensure the signature is valid only once.

Consider implementing the following changes:

  • Reintroduce the logic to fetch a unique challenge message from the server before signing.
  • Replace SIGN_MESSAGE with the retrieved challenge message in the signing process.

Also applies to: 154-155

});

const { data: confirmData, error: confirmError } = await nextApiClientFetch<TokenType>({
network,
url: 'api/v1/auth/actions/addressSignupConfirm',
url: 'api/v1/auth/actions/addressSignup',
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

Issue Detected: 'addressSignup' Endpoint Not Implemented in Backend

  • The endpoint 'api/v1/auth/actions/addressSignup' referenced in LoginForm.tsx was not found in the backend codebase.
🔗 Analysis chain

Verify the Correctness of the Updated API Endpoint

The URL for wallet signup has been changed to 'api/v1/auth/actions/addressSignup'. Ensure that this endpoint is correctly implemented on the backend and matches the expected API specification.

To verify whether the new endpoint exists, run the following script:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for the 'addressSignup' endpoint definition in the backend code.

# Expected result: Occurrences of 'addressSignup' in backend files.

rg 'addressSignup' --type javascript --type typescript --type python

Length of output: 103


Script:

#!/bin/bash
# Description: Check for the 'addressSignup' endpoint definition in the backend code with correct file type identifiers.

# Expected result: Occurrences of 'addressSignup' in backend files.

rg 'addressSignup' --type js --type ts --type py

Length of output: 128


Script:

#!/bin/bash
# Description: Verify the implementation of the 'addressSignup' endpoint in the backend code.

# Expected result: Definitions or route handlers for 'addressSignup' in backend files.

ast-grep --lang javascript --pattern $'app.$_($_) { $$$ }' --path '**/*.js' --path '**/*.ts' --path '**/*.py' | grep 'addressSignup'

Length of output: 319


Script:

#!/bin/bash
# Description: Verify the implementation of the 'addressSignup' endpoint in the backend code using ast-grep.

# Expected result: Definitions or route handlers for 'addressSignup' in backend files.

ast-grep --lang javascript --pattern $'app.$_(\"addressSignup\", $_) { $$$ }' '**/*.js' '**/*.ts' '**/*.py'

Length of output: 564


Script:

#!/bin/bash
# Description: Verify the implementation of the 'addressSignup' endpoint in the backend code using ast-grep.

# Expected result: Definitions or route handlers for 'addressSignup' in backend files.

ast-grep --lang javascript --pattern $'app.post("addressSignup", $_) { $$$ }' '**/*.js' '**/*.ts' '**/*.py'

Length of output: 568

isPolkassemblyAPI: true,
data: {
address: substrateAddress,
Expand Down Expand Up @@ -160,24 +149,9 @@ function LoginForm({ onClose }: { onClose?: () => void }) {

const substrateAddress = getSubstrateAddress(selectedAddress.address) ?? selectedAddress.address;

const { data: loginStartData, error: loginStartError } = await nextApiClientFetch<ChallengeMessage>({
network,
url: 'api/v1/auth/actions/addressLoginStart',
isPolkassemblyAPI: true,
data: {
address: substrateAddress,
wallet: selectedWallet
}
});

if (loginStartError) throw new Error(loginStartError);

const loginStartSignMessage = loginStartData?.signMessage;
if (!loginStartSignMessage) throw new Error('Challenge message not found');

const { signature: loginStartSignature } = await signRaw({
address: substrateAddress,
data: stringToHex(loginStartSignMessage),
data: stringToHex(SIGN_MESSAGE),
type: 'bytes'
});

Expand Down
5 changes: 5 additions & 0 deletions src/global/constants/signMessage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// Copyright 2019-2025 @polkassembly/fellowship authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.

export const SIGN_MESSAGE = 'Connect to Polkassembly';