@baanihali/captcha
Version:
A customizable sliding puzzle captcha component for React applications with server-side validation
174 lines (172 loc) • 6.28 kB
TypeScript
/**
* Constant value stored when a captcha is successfully verified
*/
declare const ON_VERIFY_CAPTCHA_VALUE = "verified";
/**
* Configuration options for creating a new captcha
* @interface CreateCaptchaProps
*/
interface CreateCaptchaProps {
/** Optional custom image buffer to use as the captcha background */
image?: Buffer;
/** Optional custom captcha ID (if not provided, a UUID will be generated) */
captchaId?: string;
/** Fallback local image path if remote image fetching fails */
fallbackImgPath?: string;
/**
* Function to store the captcha ID and its solution value
* @param id - The captcha ID
* @param value - The correct slider position value
*/
storeCaptchaId: (id: string, value: string) => Promise<void>;
}
/**
* Return type for captcha creation
* @interface CaptchaData
*/
interface CaptchaData {
/** Base64 encoded puzzle piece image */
puzzle: string;
/** Base64 encoded background image with puzzle piece removed */
background: string;
/** Unique captcha identifier */
id: string;
}
/**
* Return type for captcha verification
* @interface VerificationResult
*/
interface VerificationResult {
/** Whether the verification was successful */
success: boolean;
/** Reason for failure (if success is false) */
reason?: string;
}
/**
* Props for verifying a captcha
* @interface VerifyCaptchaProps
*/
interface VerifyCaptchaProps {
/** The unique captcha identifier */
captchaId: string;
/** The user's slider position as a string */
value: string;
/** Function to retrieve the stored correct position */
getCaptchaValue: (id: string) => Promise<string | null>;
/** Function to mark captcha as verified */
changeCaptchaIdOnSuccess: (id: string, value: string) => Promise<void>;
/** Optional tolerance value for correct positioning (default: 10px) */
tolerance?: number;
}
/**
* Creates a new sliding puzzle captcha with a randomly positioned puzzle piece.
*
* This function generates a captcha by:
* 1. Selecting a random horizontal position for the puzzle piece (55-249px)
* 2. Extracting a 50x50px puzzle piece from that position
* 3. Creating a background image with the puzzle piece area blacked out
* 4. Storing the correct position in your database/storage system
*
* @example
* ```typescript
* const captcha = await createCaptcha({
* fallbackImgPath: './assets/fallback.jpg',
* storeCaptchaId: async (id, value) => {
* // Store in your database/redis/etc.
* await redis.setex(id, value, 60 * 10); // Store in Redis with 10 minute TTL;
* }
* });
*
* // return captcha data to client refreshCaptcha function
* ```
*
* @param props - Configuration options for captcha creation
* @returns Promise resolving to captcha data with base64 encoded images and ID
* @throws {Error} When image processing fails or storage function throws
*
*/
declare const createCaptcha: ({ image, captchaId, fallbackImgPath, storeCaptchaId, }: CreateCaptchaProps) => Promise<CaptchaData>;
/**
* Fetches a random image for use as a captcha background.
*
* This function attempts to fetch a random image from Picsum Photos API.
* If the API request fails, it falls back to a local image file if provided.
* Note: It is recommended to give a fallback image path to ensure captcha
*
* @example
* ```typescript
* // Fetch random image from API
* const imageBuffer = await getCaptchaImage();
*
* // With fallback image
* const imageBuffer = await getCaptchaImage('./assets/fallback.jpg');
* ```
*
* @param fallbackImgPath - Optional path to a local fallback image
* @returns Promise resolving to image buffer or null if all methods fail
* @throws {Error} When both API fetch and fallback image reading fail
*
* @since 1.0.0
*/
declare const getCaptchaImage: (fallbackImgPath?: string) => Promise<ArrayBuffer | Buffer | null>;
/**
* Verifies a user's captcha solution by comparing their slider position with the stored correct position.
*
* This function:
* 1. Retrieves the stored correct position for the given captcha ID
* 2. Compares the user's answer with the correct position (allowing 10px tolerance)
* 3. Marks the captcha as verified if correct
* 4. Returns the verification result
*
* @example
* ```typescript
* const result = await verifyCaptcha({
* captchaId: 'captcha-id-123',
* value: '185', // User's slider position
* getCaptchaValue: async (id) => ...,
* changeCaptchaIdOnSuccess: async (id, value) => ...,
* tolerance: 12 // Optional, defaults to 10px
* });
*
* if (result.success) {
* console.log('Captcha verified successfully!');
* } else {
* console.log('Verification failed:', result.reason);
* }
* ```
*
* @param props - Configuration object containing all verification parameters
* @returns Promise resolving to verification result
*
* @since 1.0.0
*/
declare const verifyCaptcha: (props: VerifyCaptchaProps) => Promise<VerificationResult>;
/**
* Checks if a captcha has been successfully verified by examining its stored value.
*
* This utility function helps determine if a captcha ID corresponds to a
* successfully completed captcha challenge by comparing it against the verification constant.
*
* @example
* ```
* const isVerified = await hasCaptchaBeenVerified({
* captchaId: 'captcha-123',
* getCaptchaValue: async (id) => ....
* });
*
* if (isVerified) {
* console.log('This captcha was successfully completed');
* }
* ```
*
* @param props - Configuration object for captcha verification
* @param props.captchaId - The unique identifier for the captcha to verify
* @param props.getCaptchaValue - Function that retrieves captcha value from database/redis/etc
* @returns Promise resolving to true if the captcha has been verified
*/
interface HasCaptchaBeenVerifiedProps {
captchaId: string;
getCaptchaValue: (captchaId: string) => Promise<string | null | undefined>;
}
declare const hasCaptchaBeenVerified: (props: HasCaptchaBeenVerifiedProps) => Promise<boolean>;
export { type CaptchaData, type CreateCaptchaProps, ON_VERIFY_CAPTCHA_VALUE, type VerificationResult, type VerifyCaptchaProps, createCaptcha, getCaptchaImage, hasCaptchaBeenVerified, verifyCaptcha };