Skip to content

Commit

Permalink
Merge pull request #777 from ethereum-push-notification-service/custo…
Browse files Browse the repository at this point in the history
…m-endpoint-validation

fix: added validation for custom endpoint
  • Loading branch information
MdTeach authored Oct 12, 2023
2 parents 15ae90f + 43b8296 commit a21227a
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -338,14 +338,11 @@ const AddCriteria = ({
inviterRoles: _inviteRoles as ['OWNER' | 'ADMIN'],
};
} else {
// CATEGORY.CustomEndpoint
// TODO: validate url
return {
url: url,
};
}
} else {
// GUILD type
return {
id: guildId,
comparison: guildComparison === 'specific' ? '' : guildComparison,
Expand Down Expand Up @@ -433,7 +430,7 @@ const AddCriteria = ({
// guild condition
setGuildId((oldValue.data as GuildData).id);
setSpecificRoleId((oldValue.data as GuildData).role);
setGuildComparison((oldValue.data as GuildData).comparison);
setGuildComparison(((oldValue.data as GuildData).comparison) || GUILD_COMPARISON_OPTIONS[2].value);
}

setSelectedTypeValue(
Expand Down Expand Up @@ -525,12 +522,18 @@ const AddCriteria = ({
)}

{checkIfCustomEndpoint() && (
<Section gap="10px" flexDirection="column" alignItems="start">
<TextInput
labelName="URL"
inputValue={url}
onInputChange={(e: any) => setUrl(e.target.value)}
placeholder="e.g. abc.com"
error={!!validationErrors?.url}
/>
{!!validationErrors?.url && (
<ErrorSpan>{validationErrors?.url}</ErrorSpan>
)}
</Section>
)}
{checkIfPushInvite() && (
<Section flexDirection="column" gap="10px">
Expand Down
99 changes: 80 additions & 19 deletions packages/uiweb/src/lib/components/chat/helpers/tokenGatedGroup.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
import axios from 'axios';
import { CriteriaStateType, CriteriaValidationErrorType, Data, GuildData, Rule, TYPE } from '../types';
import {
CATEGORY,
CriteriaStateType,
CriteriaValidationErrorType,
Data,
GuildData,
PushData,
Rule,
TYPE,
} from '../types';

const handleDefineCondition = (
entryCriteria: CriteriaStateType,
Expand All @@ -18,61 +27,113 @@ const handleDefineCondition = (
}
};

const validateGUILDData = async (condition: Rule): Promise<CriteriaValidationErrorType> => {
const validateCustomEndpointData = async (
condition: Rule
): Promise<CriteriaValidationErrorType> => {
const { data, type, subcategory } = condition;
let errors: CriteriaValidationErrorType = {};

if (!(data as PushData).url) {
return { url: 'URL is missing' };
} else {
// Protocol Validation
if (
!(data as PushData)?.url!.startsWith('http://') &&
!(data as PushData).url!.startsWith('https://')
) {
return {
url: 'Invalid URL protocol. Only "http://" and "https://" are allowed.',
};
}
// URL Length Check
if ((data as PushData)?.url!.length > 2083) {
return { url: 'URL is too long.' };
}

// Check for GET and Template
if (subcategory === 'GET') {
if (!(data as PushData)?.url!.includes('{{user_address}}')) {
return {
url: `GET request URL should have the '{{user_address}}' template.`,
};
}

// Ensure proper number of expected templates
const matches = (data as PushData)?.url!.match(/{{user_address}}/g) || [];
if (matches.length > 1) {
return {
url: `GET request URL should not have multiple '{{user_address}}' templates.`,
};
}
}
}
return {};
};

const validateGUILDData = async (
condition: Rule
): Promise<CriteriaValidationErrorType> => {
const { data } = condition;
let errors: any = {};
let errors: CriteriaValidationErrorType = {};

// Check for guild ID presence
if (!(data as GuildData).id) {
errors = { ...errors, guildId: 'Guild ID is missing' };
return { ...errors, guildId: 'Guild ID is missing' };
} else {
try {
const response = await axios.get(
`https://api.guild.xyz/v1/guild/${(data as GuildData).id}`
);

if (response.status !== 200) {
errors = { ...errors, guildId: 'Guild ID is missing' };
return { ...errors, guildId: 'Guild ID is missing' };
} else {
// Validate the role values
if ((data as GuildData).role === '*') {
if (data.comparison !== 'all' && data.comparison !== 'any') {
errors = { ...errors, guildComparison: 'Invalid comparison value' };
return { ...errors, guildComparison: 'Invalid comparison value' };
}
} else if ((data as GuildData).role) {
const roleExists = response.data.roles.some(
(role: { id: number }) =>
role.id.toString() === (data as GuildData).role
);
if (!roleExists) {
errors = { ...errors, guildRole: 'Invalid Guild Role ID' };
return { ...errors, guildRole: 'Invalid Guild Role ID' };
}

// For specific role, comparison can be null or empty
if (data.comparison) {
errors = {
return {
...errors,
guildComparison: 'Comparison should be empty for specific role',
};
}
} else {
errors = { ...errors, guildRole: 'Invalid role value' };
return { ...errors, guildRole: 'Invalid role value' };
}
}
} catch (error) {
errors = { ...errors, guildId: 'Error validating Guild ID' };
return { ...errors, guildId: 'Error validating Guild ID' };
}
}

return errors;
return {};
};

const validationCriteria = async (condition: Rule):Promise<CriteriaValidationErrorType> => {
if(condition.type === TYPE.GUILD)
{
return validateGUILDData(condition);
}
const validationCriteria = async (
condition: Rule
): Promise<CriteriaValidationErrorType> => {
if (condition.type === TYPE.GUILD) {
return validateGUILDData(condition);
}
if (condition.category === CATEGORY.CustomEndpoint)
return validateCustomEndpointData(condition);

return {};
}
export { handleDefineCondition ,validationCriteria};
return {};
};
export {
handleDefineCondition,
validationCriteria,
validateCustomEndpointData,
};
Original file line number Diff line number Diff line change
Expand Up @@ -82,4 +82,7 @@ export type CriteriaValidationErrorType = {
guildRole?:string;
groupName?:string;
groupDescription?:string;

//custom endpoint errors
url?:string;
}

0 comments on commit a21227a

Please sign in to comment.