Skip to content

Commit

Permalink
Precompile Ajv Blueprint validator to avoid CSP issues (#1649)
Browse files Browse the repository at this point in the history
## Motivation for the change, related issues

[The Chrome Content Security
Policy](https://developer.chrome.com/docs/privacy-security/csp) doesn't
allow the use of eval and new Function.

This prevents people from building Chrome extensions that interact with
Playground.

This PR is an alternative to #1647 and exists because the jsonschema
library used by that PR did not generate user-friendly validation
errors. Also, if we can stick with our current validation library, we
might as well because it is more well-tested in the context of
Playground.

Fixes #1641

## Implementation details

This PR precompiles an Ajv-based Blueprint JSON validator to avoid CSP
issues as suggested in the Ajv docs
[here](https://github.com/ajv-validator/ajv/blob/9050ba1359fb87cd7c143f3c79513ea7624ea443/docs/security.md#content-security-policy).

## Testing Instructions (or ideally a Blueprint)

CI: unit tests and e2e tests
  • Loading branch information
brandonpayton authored Jul 29, 2024
1 parent 1f28d77 commit a8c0623
Show file tree
Hide file tree
Showing 6 changed files with 19,349 additions and 19 deletions.
2 changes: 1 addition & 1 deletion packages/playground/blueprints/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"extends": ["../../../.eslintrc.json"],
"ignorePatterns": ["!**/*"],
"ignorePatterns": ["!**/*", "blueprint-schema-validator.js"],
"overrides": [
{
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
Expand Down
25 changes: 23 additions & 2 deletions packages/playground/blueprints/bin/generate-schema.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import tsj from 'ts-json-schema-generator';
import fs from 'fs';
import Ajv from 'ajv';
import ajvStandaloneCode from 'ajv/dist/standalone/index.js';
import prettier from 'prettier';

/** @type {import('ts-json-schema-generator/dist/src/Config').Config} */
const config = {
Expand All @@ -11,6 +14,8 @@ const config = {

const output_path =
'packages/playground/blueprints/public/blueprint-schema.json';
const validator_output_path =
'packages/playground/blueprints/public/blueprint-schema-validator.js';

const maxRetries = 2;
async function exponentialBackoff(callback, retries = 0, delay = 1000) {
Expand Down Expand Up @@ -58,6 +63,22 @@ const schemaString = JSON.stringify(schema, null, 2)
// Naively remove TypeScript generics <T> from the schema:
.replaceAll(/%3C[a-zA-Z]+%3E/g, '')
.replaceAll(/<[a-zA-Z]+>/g, '');
fs.writeFile(output_path, schemaString, (err) => {
if (err) throw err;
fs.writeFileSync(output_path, schemaString);

const ajv = new Ajv({
discriminator: true,
code: {
source: true,
esm: true,
},
});
const validate = ajv.compile(schema);
const rawValidationCode = ajvStandaloneCode(ajv, validate);

// Use prettier to make the generated validation code more readable.
const prettierConfig = JSON.parse(fs.readFileSync('.prettierrc', 'utf8'));
const formattedValidationCode = prettier.format(
rawValidationCode,
prettierConfig
);
fs.writeFileSync(validator_output_path, formattedValidationCode);
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import type { ValidateFunction } from 'ajv';
export default BlueprintValidateFunction as ValidateFunction;
Loading

0 comments on commit a8c0623

Please sign in to comment.