I understand that it’s risky to consider this when it comes to security. However I am currently planning a project with the following ambitions:
Create a grammar using Nearley.js.
Use that grammar to store a function in my database for example:
"IF(G.cells[id]!=NULL){INVALIDMOVE}, playerID->G.cells[id]"
That function gets translated in the following parser in the following way:
function translateAST(ast) {
switch (ast.type) {
case 'condition':
return `
if (${translateExpr(ast.condition)}) {
return ${translateAction(ast.action)};
}
`;
case 'assignment':
return `
${ast.target} = ${translateExpr(ast.value)};
`;
default:
throw new Error(`Unknown AST node type: ${ast.type}`);
}
}
function translateExpr(expr) {
switch (expr.type) {
case 'notEqual':
return `${expr.left} !== ${expr.right}`;
case 'identifier':
return expr.name;
default:
throw new Error(`Unknown expression type: ${expr.type}`);
}
}
function translateAction(action) {
switch (action.type) {
case 'action':
if (action.name === 'INVALID_MOVE') {
return 'INVALID_MOVE';
}
default:
throw new Error(`Unknown action type: ${action.type}`);
}
}
Then after we have parsed this
function generateMoveFunction(code) {
return function({ G, playerID }, id) {
// Use a closure to safely execute the code
const func = new Function('G', 'playerID', 'id', `
${code}
`);
return func(G, playerID, id);
};
}
// Example usage
const moveString = "IF(G.cells[id]!=NULL){INVALIDMOVE}, playerID->G.cells[id]";
const ast = parseMove(moveString);
const code = translateAST(ast);
const moveFunction = generateMoveFunction(code);
Then pass this moveFunction as a move for a library
const moves = {
clickCell: moveFunction,
};
// Boardgame.io game configuration
const MyGame = {
setup: () => ({ cells: Array(9).fill(null) }),
moves: moves,
};
Is this a bad idea?