From 4872b06a289c9cf44b95c6a0f553f93d5ab78849 Mon Sep 17 00:00:00 2001 From: Quincy Morgan Date: Sat, 21 Mar 2020 13:16:40 -0700 Subject: [PATCH] Randomize form field ids to thwart browser memory and help with embedding iD (close #6444) --- modules/ui/commit.js | 8 +++++--- modules/ui/field.js | 5 +++-- modules/ui/fields/check.js | 3 +-- modules/ui/fields/combo.js | 2 +- modules/ui/fields/input.js | 4 ++-- modules/ui/fields/localized.js | 2 +- modules/ui/fields/maxspeed.js | 4 ++-- modules/ui/fields/textarea.js | 2 +- modules/ui/fields/wikipedia.js | 2 +- modules/util/index.js | 1 + modules/util/util.js | 7 +++++++ 11 files changed, 25 insertions(+), 15 deletions(-) diff --git a/modules/ui/commit.js b/modules/ui/commit.js index 0047ee422..1c4e0dbdb 100644 --- a/modules/ui/commit.js +++ b/modules/ui/commit.js @@ -11,7 +11,7 @@ import { uiChangesetEditor } from './changeset_editor'; import { uiSectionChanges } from './sections/changes'; import { uiCommitWarnings } from './commit_warnings'; import { uiSectionRawTagEditor } from './sections/raw_tag_editor'; -import { utilArrayGroupBy, utilRebind } from '../util'; +import { utilArrayGroupBy, utilRebind, utilUniqueDomId } from '../util'; import { utilDetect } from '../util/detect'; @@ -311,14 +311,16 @@ export function uiCommit(context) { .append('div') .attr('class', 'request-review'); + var id = utilUniqueDomId('commit-input-request-review'); + var labelEnter = requestReviewEnter .append('label') - .attr('for', 'commit-input-request-review'); + .attr('for', id); labelEnter .append('input') .attr('type', 'checkbox') - .attr('id', 'commit-input-request-review'); + .attr('id', id); labelEnter .append('span') diff --git a/modules/ui/field.js b/modules/ui/field.js index 7867102c8..c0496015c 100644 --- a/modules/ui/field.js +++ b/modules/ui/field.js @@ -10,7 +10,7 @@ import { geoExtent } from '../geo/extent'; import { uiFieldHelp } from './field_help'; import { uiFields } from './fields'; import { uiTagReference } from './tag_reference'; -import { utilRebind } from '../util'; +import { utilRebind, utilUniqueDomId } from '../util'; export function uiField(context, presetField, entityIDs, options) { @@ -24,6 +24,7 @@ export function uiField(context, presetField, entityIDs, options) { var dispatch = d3_dispatch('change', 'revert'); var field = Object.assign({}, presetField); // shallow copy + field.domId = utilUniqueDomId('form-field-' + field.safeid); var _show = options.show; var _state = ''; var _tags = {}; @@ -123,7 +124,7 @@ export function uiField(context, presetField, entityIDs, options) { var labelEnter = enter .append('label') .attr('class', 'field-label') - .attr('for', function(d) { return 'preset-input-' + d.safeid; }); + .attr('for', function(d) { return d.domId; }); var textEnter = labelEnter .append('span') diff --git a/modules/ui/fields/check.js b/modules/ui/fields/check.js index 8f634b4aa..156967469 100644 --- a/modules/ui/fields/check.js +++ b/modules/ui/fields/check.js @@ -104,7 +104,7 @@ export function uiFieldCheck(field, context) { .append('input') .property('indeterminate', field.type !== 'defaultCheck') .attr('type', 'checkbox') - .attr('id', 'preset-input-' + field.safeid); + .attr('id', field.domId); enter .append('span') @@ -114,7 +114,6 @@ export function uiFieldCheck(field, context) { if (field.type === 'onewayCheck') { enter .append('a') - .attr('id', 'preset-input-' + field.safeid + '-reverser') .attr('class', 'reverser button' + (reverserHidden() ? ' hide' : '')) .attr('href', '#') .append('span') diff --git a/modules/ui/fields/combo.js b/modules/ui/fields/combo.js index b5fe3c793..33af5159e 100644 --- a/modules/ui/fields/combo.js +++ b/modules/ui/fields/combo.js @@ -381,7 +381,7 @@ export function uiFieldCombo(field, context) { input = input.enter() .append('input') .attr('type', 'text') - .attr('id', 'preset-input-' + field.safeid) + .attr('id', field.domId) .attr('maxlength', context.maxCharsForTagValue()) .call(utilNoAuto) .call(initCombo, selection) diff --git a/modules/ui/fields/input.js b/modules/ui/fields/input.js index 514f5833c..800963605 100644 --- a/modules/ui/fields/input.js +++ b/modules/ui/fields/input.js @@ -52,7 +52,7 @@ export function uiFieldText(field, context) { input = input.enter() .append('input') .attr('type', field.type === 'identifier' ? 'text' : field.type) - .attr('id', fieldID) + .attr('id', field.domId) .attr('maxlength', context.maxCharsForTagValue()) .classed(field.type, true) .call(utilNoAuto) @@ -71,7 +71,7 @@ export function uiFieldText(field, context) { var countryCode = extent && countryCoder.iso1A2Code(extent.center()); var format = countryCode && _phoneFormats[countryCode.toLowerCase()]; if (format) { - wrap.selectAll('#' + fieldID) + wrap.selectAll('#' + field.domId) .attr('placeholder', format); } diff --git a/modules/ui/fields/localized.js b/modules/ui/fields/localized.js index a7a5d886e..870b53275 100644 --- a/modules/ui/fields/localized.js +++ b/modules/ui/fields/localized.js @@ -167,7 +167,7 @@ export function uiFieldLocalized(field, context) { input = input.enter() .append('input') .attr('type', 'text') - .attr('id', 'preset-input-' + field.safeid) + .attr('id', field.domId) .attr('class', 'localized-main') .attr('maxlength', context.maxCharsForTagValue()) .call(utilNoAuto) diff --git a/modules/ui/fields/maxspeed.js b/modules/ui/fields/maxspeed.js index bfd9b0f55..e759abf63 100644 --- a/modules/ui/fields/maxspeed.js +++ b/modules/ui/fields/maxspeed.js @@ -35,13 +35,13 @@ export function uiFieldMaxspeed(field, context) { .merge(wrap); - input = wrap.selectAll('#preset-input-' + field.safeid) + input = wrap.selectAll('#' + field.domId) .data([0]); input = input.enter() .append('input') .attr('type', 'text') - .attr('id', 'preset-input-' + field.safeid) + .attr('id', field.domId) .attr('maxlength', context.maxCharsForTagValue() - 4) .call(utilNoAuto) .call(speedCombo) diff --git a/modules/ui/fields/textarea.js b/modules/ui/fields/textarea.js index f379ee007..acdb4c55f 100644 --- a/modules/ui/fields/textarea.js +++ b/modules/ui/fields/textarea.js @@ -29,7 +29,7 @@ export function uiFieldTextarea(field, context) { input = input.enter() .append('textarea') - .attr('id', 'preset-input-' + field.safeid) + .attr('id', field.domId) .attr('maxlength', context.maxCharsForTagValue()) .call(utilNoAuto) .on('input', change(true)) diff --git a/modules/ui/fields/wikipedia.js b/modules/ui/fields/wikipedia.js index 94e810aaa..c540ffab5 100644 --- a/modules/ui/fields/wikipedia.js +++ b/modules/ui/fields/wikipedia.js @@ -113,7 +113,7 @@ export function uiFieldWikipedia(field, context) { .append('input') .attr('type', 'text') .attr('class', 'wiki-title') - .attr('id', `preset-input-${field.safeid}`) + .attr('id', field.domId) .attr('maxlength', context.maxCharsForTagValue() - 4) .call(utilNoAuto) .call(titleCombo) diff --git a/modules/util/index.js b/modules/util/index.js index b6a5f8507..e3e6f39be 100644 --- a/modules/util/index.js +++ b/modules/util/index.js @@ -47,4 +47,5 @@ export { utilTagDiff } from './util'; export { utilTagText } from './util'; export { utilTiler } from './tiler'; export { utilTriggerEvent } from './trigger_event'; +export { utilUniqueDomId } from './util'; export { utilWrap } from './util'; diff --git a/modules/util/util.js b/modules/util/util.js index 2459d04a6..da5d65311 100644 --- a/modules/util/util.js +++ b/modules/util/util.js @@ -514,3 +514,10 @@ export function utilHashcode(str) { export function utilSafeClassName(str) { return str.toLowerCase().replace(/[^a-z0-9]+/g, '_'); } + +// Returns string based on `str` that is highly unlikely to collide with an id +// used previously or that's present elsewhere in the document. Useful for preventing +// browser-provided autofills or when embedding iD on pages with unknown elements. +export function utilUniqueDomId(str) { + return 'ideditor-' + utilSafeClassName(str) + '-' + new Date().getTime().toString(); +}