@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
JavaScript
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
};
}