Skip to content

Commit

Permalink
Merge pull request #125 from hkbertoson/script-changes
Browse files Browse the repository at this point in the history
Script changes
  • Loading branch information
hkbertoson authored Dec 11, 2024
2 parents 6372405 + 31d452f commit 68326d6
Show file tree
Hide file tree
Showing 10 changed files with 121 additions and 41 deletions.
5 changes: 5 additions & 0 deletions .changeset/quiet-readers-beg.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"astro-turnstile": minor
---

Updated to use data attribute instead of comment
5 changes: 5 additions & 0 deletions .changeset/rare-clouds-eat.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"astro-turnstile": minor
---

Updated script to only inject on pages where component is rendered
23 changes: 0 additions & 23 deletions package/lib/client.ts

This file was deleted.

7 changes: 5 additions & 2 deletions package/lib/components/TurnstileForm.astro
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const siteUrl = Astro.site;
id="at-turnstile-captcha-form"
data-siteurl={siteUrl}
data-captcha={config.endpointPath}
data-turnstile-container
action={action}
method={method}
enctype={enctype}
Expand All @@ -52,7 +53,7 @@ const siteUrl = Astro.site;
<script>
// Get the form element
const form = document.getElementById(
'at-turnstile-captcha-form'
'at-turnstile-captcha-form',
) as HTMLFormElement;

const turnstileConfig = form.dataset;
Expand All @@ -70,7 +71,9 @@ const siteUrl = Astro.site;
if (typeof value === 'string') {
urlEncodedFormData.append(key, value);
} else {
console.warn(`Invalid form data value for key: ${key}, Skipping...`);
console.warn(
`Invalid form data value for key: ${key}, Skipping...`,
);
}
});

Expand Down
7 changes: 5 additions & 2 deletions package/lib/components/TurnstileWidget.astro
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ const getStyleSettings = (size: string): Dimensions => {
// If the style settings do not exist, throw an error
throw new AstroError(
`Invalid size: ${size}`,
`'size' must be one of the following: ${Object.keys(sizes).join(', ')}.`
`'size' must be one of the following: ${Object.keys(sizes).join(', ')}.`,
);
};
Expand All @@ -71,6 +71,7 @@ const {
data-sitekey={TURNSTILE_SITE_KEY}
data-theme={theme}
data-size={size}
data-turnstile-container
>
</div>

Expand All @@ -96,7 +97,9 @@ const {
// see https://developers.cloudflare.com/turnstile/get-started/client-side-rendering/#explicitly-render-the-turnstile-widget
function onloadTurnstileCallback() {
// Get the Turnstile configuration from the Turnstile form element
const {dataset: TConfig} = document.getElementById('at-turnstile-captcha');
const {dataset: TConfig} = document.getElementById(
'at-turnstile-captcha',
);

// Render the Turnstile widget with the configuration
turnstile.render('#at-turnstile-captcha', {
Expand Down
1 change: 0 additions & 1 deletion package/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
"default": "./src/index.ts"
},
"./schema": "./src/schema.ts",
"./client": "./lib/client.ts",
"./server": "./lib/server.ts",
"./components/TurnstileWidget": "./lib/components/TurnstileWidget.astro",
"./components/TurnstileForm": "./lib/components/TurnstileForm.astro"
Expand Down
13 changes: 5 additions & 8 deletions package/src/integration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export const astroTurnstile = defineIntegration({
command,
config,
addDevToolbarApp,
addMiddleware,
} = params;

// Log startup message
Expand Down Expand Up @@ -122,16 +123,10 @@ export const astroTurnstile = defineIntegration({

// Inject the required Turnstile client-side script if not disabled
if (!disableClientScript) {
verbose && logger.info(loggerStrings.injectScript);
injectScript('page', `import '${name}/client'`);
verbose && logger.info(loggerStrings.injectMiddleware);
addMiddleware({entrypoint: resolve('./middleware.ts'), order: 'post'});
}

/*
name: 'Astro Turnstile',
id: 'astro-turnstile-dev-toolbar',
icon: svgIcons.turnstile,
*/
// Add Development Toolbar App for Astro Turnstile testing
if (!disableDevToolbar) {
verbose && logger.info(loggerStrings.addDevToolbarApp);
Expand Down Expand Up @@ -164,6 +159,8 @@ export const astroTurnstile = defineIntegration({
},
});



// Log completion message
verbose && logger.info(loggerStrings.setupComplete);
},
Expand Down
91 changes: 91 additions & 0 deletions package/src/middleware.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import type { MiddlewareHandler } from "astro";

const COMPONENT_IDENTIFIER = 'data-turnstile-container';
const TURNSTILE_SCRIPT = `
<script
src="https://challenges.cloudflare.com/turnstile/v0/api.js?onload=onloadTurnstileCallback"
async
defer
id="turnstile-script">
</script>`;

const MAX_SCAN_BYTES = 16384; // 16KB
let bytesScanned = 0;

export const onRequest: MiddlewareHandler = async (_, next) => {
const response = await next();

const contentType = response.headers.get('Content-Type');
if (!contentType?.includes('text/html') || !response.body) {
return response;
}

const transformedBody = response.body
.pipeThrough(new TextDecoderStream())
.pipeThrough(createFastScriptInjectionTransform())
.pipeThrough(new TextEncoderStream());

return new Response(transformedBody, {
status: response.status,
statusText: response.statusText,
headers: response.headers
});
};

function createFastScriptInjectionTransform(): TransformStream<string, string> {
let hasInjected = false;
let hasFoundComponent = false;
let buffer = '';

return new TransformStream({
transform(chunk: string, controller) {
// Fast path: already injected or scanned too much
if (hasInjected || bytesScanned > MAX_SCAN_BYTES) {
controller.enqueue(chunk);
return;
}

bytesScanned += chunk.length;

// Fast path: haven't found component yet
if (!hasFoundComponent) {
// Look for the data attribute
if (chunk.includes(COMPONENT_IDENTIFIER)) {
hasFoundComponent = true;
buffer = chunk;
} else {
controller.enqueue(chunk);
return;
}
} else {
buffer += chunk;
}

const headCloseIndex = buffer.indexOf('</head>');
if (headCloseIndex === -1) {
if (buffer.length > MAX_SCAN_BYTES) {
controller.enqueue(buffer);
buffer = '';
hasInjected = true;
}
return;
}

const injectedContent =
buffer.slice(0, headCloseIndex) +
TURNSTILE_SCRIPT +
buffer.slice(headCloseIndex);

controller.enqueue(injectedContent);
hasInjected = true;
buffer = '';
},

flush(controller) {
if (buffer) {
controller.enqueue(buffer);
}
bytesScanned = 0;
}
});
}
2 changes: 1 addition & 1 deletion package/src/strings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ export const loggerStrings = {
setup: 'Turnstile integration setup...',
configSiteMissing: `Astro Config Error: 'site' is not defined, it is recommended to define 'site' in your Astro config. (https://docs.astro.build/en/reference/configuration-reference/#site)\nFalling back to 'window.location.origin'.`,
updateConfig: 'Updating Astro config with Turnstile environment variables...',
injectScript: 'Injecting Turnstile client script...',
injectMiddleware: 'Injecting Turnstile middleware...',
injectRoute: (value: string) => `Injecting Turnstile route at ${value}...`,
virtualImports: 'Adding Virtual Import modules...',
setupComplete: 'Turnstile integration setup complete.',
Expand Down
8 changes: 4 additions & 4 deletions playground/src/pages/index.astro
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,22 @@ if (Astro.request.method === 'POST') {

<Layout title="Welcome to Astro.">
<main>
<!-- <form>
<form>
<label>
Username:
<input type="text" name="username" required />
</label>
<button type="submit">Submit</button>
<TurnstileWidget />
</form> -->
<main>
</form>
<!-- <main>
<TurnstileForm action="/" method={'POST'} enctype={'submit'}>
<label>
Username:
<input type="text" name="username" required />
</label>
</TurnstileForm>
</main>
</main> -->
</main>

<style is:global>
Expand Down

0 comments on commit 68326d6

Please sign in to comment.