0
Fork 0
mirror of https://github.com/withastro/astro.git synced 2024-12-30 22:03:56 -05:00

Rename Action query param to _action (#12510)

* rename _astroAction to _action

* changeset
This commit is contained in:
Ben Holmes 2024-11-25 03:43:15 -05:00 committed by GitHub
parent 30c78ba306
commit 14feaf30e1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 19 additions and 15 deletions

View file

@ -0,0 +1,6 @@
---
'@astrojs/react': minor
'astro': minor
---
Changes the generated URL query param from `_astroAction` to `_action` when submitting a form using Actions. This avoids leaking the framework name into the URL bar, which may be considered a security issue.

View file

@ -162,7 +162,7 @@ test.describe('Astro Actions - Blog', () => {
await page.goto(astro.resolveUrl('/sum')); await page.goto(astro.resolveUrl('/sum'));
const submitButton = page.getByTestId('submit'); const submitButton = page.getByTestId('submit');
await submitButton.click(); await submitButton.click();
await expect(page).toHaveURL(astro.resolveUrl('/sum?_astroAction=sum')); await expect(page).toHaveURL(astro.resolveUrl('/sum?_action=sum'));
const p = page.locator('p').nth(0); const p = page.locator('p').nth(0);
await expect(p).toContainText('Form result: {"data":3}'); await expect(p).toContainText('Form result: {"data":3}');
}); });

View file

@ -6,7 +6,7 @@ export const RESOLVED_VIRTUAL_INTERNAL_MODULE_ID = '\0astro:internal-actions';
export const NOOP_ACTIONS = '\0noop-actions'; export const NOOP_ACTIONS = '\0noop-actions';
export const ACTION_QUERY_PARAMS = { export const ACTION_QUERY_PARAMS = {
actionName: '_astroAction', actionName: '_action',
actionPayload: '_astroActionPayload', actionPayload: '_astroActionPayload',
}; };

View file

@ -220,7 +220,7 @@ describe('Astro Actions', () => {
}); });
it('Response middleware fallback - POST', async () => { it('Response middleware fallback - POST', async () => {
const req = new Request('http://example.com/user?_astroAction=getUser', { const req = new Request('http://example.com/user?_action=getUser', {
method: 'POST', method: 'POST',
body: new FormData(), body: new FormData(),
headers: { headers: {
@ -237,7 +237,7 @@ describe('Astro Actions', () => {
it('Response middleware fallback - cookie forwarding', async () => { it('Response middleware fallback - cookie forwarding', async () => {
const req = new Request( const req = new Request(
'http://example.com/user?_astroAction=getUser&actionCookieForwarding=true', 'http://example.com/user?_action=getUser&actionCookieForwarding=true',
{ {
method: 'POST', method: 'POST',
body: new FormData(), body: new FormData(),
@ -255,7 +255,7 @@ describe('Astro Actions', () => {
}); });
it('Respects custom errors - POST', async () => { it('Respects custom errors - POST', async () => {
const req = new Request('http://example.com/user-or-throw?_astroAction=getUserOrThrow', { const req = new Request('http://example.com/user-or-throw?_action=getUserOrThrow', {
method: 'POST', method: 'POST',
body: new FormData(), body: new FormData(),
headers: { headers: {
@ -273,7 +273,7 @@ describe('Astro Actions', () => {
it('Respects custom errors - cookie forwarding', async () => { it('Respects custom errors - cookie forwarding', async () => {
const req = new Request( const req = new Request(
'http://example.com/user-or-throw?_astroAction=getUserOrThrow&actionCookieForwarding=true', 'http://example.com/user-or-throw?_action=getUserOrThrow&actionCookieForwarding=true',
{ {
method: 'POST', method: 'POST',
body: new FormData(), body: new FormData(),
@ -320,8 +320,8 @@ describe('Astro Actions', () => {
assert.equal('safe' in data, true); assert.equal('safe' in data, true);
}); });
it('Ignores `_astroAction` name for GET requests', async () => { it('Ignores action name for GET requests', async () => {
const req = new Request('http://example.com/user-or-throw?_astroAction=getUserOrThrow', { const req = new Request('http://example.com/user-or-throw?_action=getUserOrThrow', {
method: 'GET', method: 'GET',
}); });
const res = await app.render(req); const res = await app.render(req);

View file

@ -126,11 +126,7 @@ async function getFormState({ result }) {
* This matches the endpoint path. * This matches the endpoint path.
* @example "/_actions/blog.like" * @example "/_actions/blog.like"
*/ */
const actionName = const actionName = searchParams.get('_action');
searchParams.get('_astroAction') ??
/* Legacy. TODO: remove for stable */ formData
.get('_astroAction')
?.toString();
if (!actionKey || !actionName) return undefined; if (!actionKey || !actionName) return undefined;

View file

@ -26,7 +26,7 @@ export function experimental_withState<T>(action: FormFn<T>) {
// Called by React when form state is passed from the server. // Called by React when form state is passed from the server.
// If the action names match, React returns this state from `useActionState()`. // If the action names match, React returns this state from `useActionState()`.
callback.$$IS_SIGNATURE_EQUAL = (incomingActionName: string) => { callback.$$IS_SIGNATURE_EQUAL = (incomingActionName: string) => {
const actionName = new URLSearchParams(action.toString()).get('_astroAction'); const actionName = new URLSearchParams(action.toString()).get('_action');
return actionName === incomingActionName; return actionName === incomingActionName;
}; };
@ -46,7 +46,9 @@ export function experimental_withState<T>(action: FormFn<T>) {
*/ */
export async function experimental_getActionState<T>({ export async function experimental_getActionState<T>({
request, request,
}: { request: Request }): Promise<T> { }: {
request: Request;
}): Promise<T> {
const contentType = request.headers.get('Content-Type'); const contentType = request.headers.get('Content-Type');
if (!contentType || !isFormRequest(contentType)) { if (!contentType || !isFormRequest(contentType)) {
throw new AstroError( throw new AstroError(