From 2c3ae9eba794855068ecae5e0fc08daa99588ff0 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Tue, 24 Sep 2024 19:29:10 -0700 Subject: [PATCH] fix(developer): prevent invalid string ids Adds checks for invalid string IDs and corresponding unit tests. Fixes: #12451 --- .../src/compiler/ldml-compiler-messages.ts | 17 ++++++++++++---- developer/src/kmc-ldml/src/compiler/vars.ts | 20 +++++++++++++++++++ .../vars/fail-invalid-identifiers.xml | 17 ++++++++++++++++ developer/src/kmc-ldml/test/test-vars.ts | 10 ++++++++++ 4 files changed, 60 insertions(+), 4 deletions(-) create mode 100644 developer/src/kmc-ldml/test/fixtures/sections/vars/fail-invalid-identifiers.xml diff --git a/developer/src/kmc-ldml/src/compiler/ldml-compiler-messages.ts b/developer/src/kmc-ldml/src/compiler/ldml-compiler-messages.ts index 1b6752bdee8..901f4b00227 100644 --- a/developer/src/kmc-ldml/src/compiler/ldml-compiler-messages.ts +++ b/developer/src/kmc-ldml/src/compiler/ldml-compiler-messages.ts @@ -187,7 +187,13 @@ export class LdmlCompilerMessages { static Error_UnparseableReorderSet = (o: { from: string, set: string }) => m(this.ERROR_UnparseableReorderSet, `Illegal UnicodeSet "${def(o.set)}" in reorder "${def(o.from)}`); - // Available: 0x029 + static ERROR_InvalidVariableIdentifer = SevError | 0x0029; + static Error_InvalidVariableIdentifer = (o: { id: string }) => m( + this.ERROR_InvalidVariableIdentifer, + `Invalid variable identifier "\\u${def(o.id)}". Identifiers must be between 1 and 32 characters, and can use A-Z, a-z, 0-9, and _.`, + ); + + // Available: 0x02A-0x2F static ERROR_InvalidQuadEscape = SevError | 0x0030; static Error_InvalidQuadEscape = (o: { cp: number }) => @@ -202,9 +208,12 @@ export class LdmlCompilerMessages { m(this.ERROR_UnparseableTransformFrom, `Invalid transform from="${def(o.from)}": "${def(o.message)}"`); static ERROR_IllegalTransformDollarsign = SevErrorTransform | 0x01; - static Error_IllegalTransformDollarsign = (o: { from: string }) => - m(this.ERROR_IllegalTransformDollarsign, `Invalid transform from="${def(o.from)}": Unescaped dollar-sign ($) is not valid transform syntax.`, - '**Hint**: Use `\\$` to match a literal dollar-sign.'); + static Error_IllegalTransformDollarsign = (o: { from: string }) => m( + this.ERROR_IllegalTransformDollarsign, + `Invalid transform from="${def(o.from)}": Unescaped dollar-sign ($) is not valid transform syntax.`, + `**Hint**: Use \`\\$\` to match a literal dollar-sign. If this precedes a variable name, `+ + `the variable name may not be valid (A-Z, a-z, 0-9, _, 32 character maximum).` + ); static ERROR_TransformFromMatchesNothing = SevErrorTransform | 0x02; static Error_TransformFromMatchesNothing = (o: { from: string }) => diff --git a/developer/src/kmc-ldml/src/compiler/vars.ts b/developer/src/kmc-ldml/src/compiler/vars.ts index 39bc9304af9..3fc39f0d011 100644 --- a/developer/src/kmc-ldml/src/compiler/vars.ts +++ b/developer/src/kmc-ldml/src/compiler/vars.ts @@ -40,6 +40,14 @@ export class VarsCompiler extends SectionCompiler { return valid; } + private validateIdentifier(id: string) { + if(!id.match(VariableParser.ID)) { // From DTD + this.callbacks.reportMessage(LdmlCompilerMessages.Error_InvalidVariableIdentifer({id})); + return false; + } + return true; + } + private validateVars(st: Substitutions): boolean { let valid = true; const variables = this.keyboard3?.variables; @@ -67,6 +75,10 @@ export class VarsCompiler extends SectionCompiler { if (variables) { // Strings for (const { id, value } of variables.string) { + if(!this.validateIdentifier(id)) { + valid = false; + continue; + } addId(id); const stringrefs = VariableParser.allStringReferences(value); for(const ref of stringrefs) { @@ -81,6 +93,10 @@ export class VarsCompiler extends SectionCompiler { } // Sets for (const { id, value } of variables.set) { + if(!this.validateIdentifier(id)) { + valid = false; + continue; + } addId(id); allSets.add(id); // check for illegal references, here. @@ -103,6 +119,10 @@ export class VarsCompiler extends SectionCompiler { } // UnicodeSets for (const { id, value } of variables.uset) { + if(!this.validateIdentifier(id)) { + valid = false; + continue; + } addId(id); allUnicodeSets.add(id); const stringrefs = VariableParser.allStringReferences(value); diff --git a/developer/src/kmc-ldml/test/fixtures/sections/vars/fail-invalid-identifiers.xml b/developer/src/kmc-ldml/test/fixtures/sections/vars/fail-invalid-identifiers.xml new file mode 100644 index 00000000000..880864fd4e6 --- /dev/null +++ b/developer/src/kmc-ldml/test/fixtures/sections/vars/fail-invalid-identifiers.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/developer/src/kmc-ldml/test/test-vars.ts b/developer/src/kmc-ldml/test/test-vars.ts index d513574ee8e..8eef17af25c 100644 --- a/developer/src/kmc-ldml/test/test-vars.ts +++ b/developer/src/kmc-ldml/test/test-vars.ts @@ -121,6 +121,16 @@ describe('vars', function () { LdmlCompilerMessages.Error_DuplicateVariable({ids: 'upper, y'}) ], }, + { + subpath: 'sections/vars/fail-invalid-identifiers.xml', + errors: [ + LdmlCompilerMessages.Error_InvalidVariableIdentifer({id: 'invalid-string'}), + LdmlCompilerMessages.Error_InvalidVariableIdentifer({id: 'invalid-set'}), + LdmlCompilerMessages.Error_InvalidVariableIdentifer({id: 'invalid-uset'}), + LdmlCompilerMessages.Error_InvalidVariableIdentifer({id: 'a_marker_name_more_than_32_chars_long'}), + LdmlCompilerMessages.Error_InvalidVariableIdentifer({id: '😡'}), + ], + }, { subpath: 'sections/vars/fail-uset-props1.xml', errors: [