UNPKG

@astro-utils/forms

Version:

Server component for Astro (call server functions from client side with validation and state management)

43 lines (42 loc) 1.78 kB
import Tokens from 'csrf'; import { promisify } from 'node:util'; import { createLock } from '../utils.js'; import { getFormValue, isPost } from './post.js'; import { FORM_OPTIONS, getFormOptions } from '../settings.js'; export const DEFAULT_SETTINGS = { formFiled: 'request-validation-token', sessionFiled: 'request-validation-secret' }; const tokens = new Tokens(); const createSecret = () => promisify(tokens.secret.bind(tokens))(); export async function ensureValidationSecret(astro, formOptions = getFormOptions(astro)) { var _a; const currentSession = astro.locals.session; return currentSession[_a = formOptions.csrf.sessionFiled] ?? (currentSession[_a] = await createSecret()); } export async function validateFrom(astro) { var _a; const lock = (_a = astro.request).validateFormLock ?? (_a.validateFormLock = createLock()); await lock.acquireAsync(); try { if (!isPost(astro) || typeof astro.request.formData.requestFormValid === 'boolean') { return astro.request.formData.requestFormValid; } const validationSecret = await ensureValidationSecret(astro); const validateToken = await getFormValue(astro.request, getFormOptions(astro).csrf.formFiled); const requestValid = validateToken && validationSecret && typeof validateToken == 'string' && tokens.verify(validationSecret, validateToken); return astro.request.formData.requestFormValid = Boolean(requestValid); } finally { lock.release(); } } export async function createFormToken(astro) { const validationSecret = await ensureValidationSecret(astro); const token = tokens.create(validationSecret); return { token, filed: FORM_OPTIONS.csrf.formFiled }; }