diff --git a/.changelog/11117.txt b/.changelog/11117.txt new file mode 100644 index 000000000..6d18e5abd --- /dev/null +++ b/.changelog/11117.txt @@ -0,0 +1,4 @@ +```release-note:improvement +ui: Add uri guard to prevent future URL encoding issues +``` + diff --git a/ui/packages/consul-ui/app/components/auth-dialog/index.hbs b/ui/packages/consul-ui/app/components/auth-dialog/index.hbs index c2cc07b6f..afeeba0fd 100644 --- a/ui/packages/consul-ui/app/components/auth-dialog/index.hbs +++ b/ui/packages/consul-ui/app/components/auth-dialog/index.hbs @@ -6,13 +6,13 @@ {{! This DataSource just permanently listens to any changes to the users }} {{! token, whether thats a new token, a changed token or a deleted token }} {{! This DataSink is just used for logging in from the form, }} {{! or logging out via the exposed logout function }} {{yield}} diff --git a/ui/packages/consul-ui/app/components/data-source/README.mdx b/ui/packages/consul-ui/app/components/data-source/README.mdx index 5c872001a..559eff6bb 100644 --- a/ui/packages/consul-ui/app/components/data-source/README.mdx +++ b/ui/packages/consul-ui/app/components/data-source/README.mdx @@ -16,7 +16,7 @@ class SomethingRepository extends Service { ```hbs preview-template @@ -26,6 +26,9 @@ as |source|> ``` + +Please make sure you use the `uri` helper to specify src URIs, this ensures that it is very difficult to miss any URL encoding problems. If you don't use the `uri` helper then an error will be thrown. + ## Attributes | Argument | Type | Default | Description | @@ -55,7 +58,7 @@ Straightforward usage can use `mut` to easily update data within a template usin ```hbs {{! listen for HTTP API changes}} @@ -72,7 +75,7 @@ Straightforward usage can use `mut` to easily update data within a template usin {{! listen for Settings (local storage) changes}} @@ -85,7 +88,7 @@ A property approach to easily update data within a template ```hbs {{! listen for HTTP API changes}} {{#if source.error}} Something went wrong! @@ -115,19 +118,19 @@ DataSources can also be recursively nested for loading in series as opposed to i {{! listen for HTTP API changes}} {{source.data.Service.Service.Name}} <== Detailed information for the first service diff --git a/ui/packages/consul-ui/app/components/empty-state/index.hbs b/ui/packages/consul-ui/app/components/empty-state/index.hbs index c55053495..fcbeeaa4f 100644 --- a/ui/packages/consul-ui/app/components/empty-state/index.hbs +++ b/ui/packages/consul-ui/app/components/empty-state/index.hbs @@ -22,7 +22,7 @@ {{on "click" login}} > {{#if token.AccessorID}} diff --git a/ui/packages/consul-ui/app/components/hashicorp-consul/index.hbs b/ui/packages/consul-ui/app/components/hashicorp-consul/index.hbs index 83ad29ad9..b0c2a5f9c 100644 --- a/ui/packages/consul-ui/app/components/hashicorp-consul/index.hbs +++ b/ui/packages/consul-ui/app/components/hashicorp-consul/index.hbs @@ -26,7 +26,7 @@ {{#let components.MenuItem components.MenuSeparator as |MenuItem MenuSeparator|}} diff --git a/ui/packages/consul-ui/app/components/policy-selector/index.hbs b/ui/packages/consul-ui/app/components/policy-selector/index.hbs index 98d0a9630..d47314aa6 100644 --- a/ui/packages/consul-ui/app/components/policy-selector/index.hbs +++ b/ui/packages/consul-ui/app/components/policy-selector/index.hbs @@ -88,8 +88,8 @@ diff --git a/ui/packages/consul-ui/app/helpers/uri.js b/ui/packages/consul-ui/app/helpers/uri.js index 8c3667ea1..7c0692c1c 100644 --- a/ui/packages/consul-ui/app/helpers/uri.js +++ b/ui/packages/consul-ui/app/helpers/uri.js @@ -5,6 +5,8 @@ const templateRe = /\${([A-Za-z.0-9_-]+)}/g; let render; export default class UriHelper extends Helper { @service('encoder') encoder; + @service('data-source/service') data; + constructor() { super(...arguments); if (typeof render !== 'function') { @@ -13,6 +15,6 @@ export default class UriHelper extends Helper { } compute([template, vars]) { - return render(template, vars); + return this.data.uri(render(template, vars)); } } diff --git a/ui/packages/consul-ui/app/services/data-sink/service.js b/ui/packages/consul-ui/app/services/data-sink/service.js index 31b051252..6e64c558c 100644 --- a/ui/packages/consul-ui/app/services/data-sink/service.js +++ b/ui/packages/consul-ui/app/services/data-sink/service.js @@ -1,17 +1,15 @@ import Service, { inject as service } from '@ember/service'; const parts = function(uri) { + uri = uri.toString(); if (uri.indexOf('://') === -1) { uri = `consul://${uri}`; } return uri.split('://'); }; export default class DataSinkService extends Service { - @service('data-sink/protocols/http') - consul; - - @service('data-sink/protocols/local-storage') - settings; + @service('data-sink/protocols/http') consul; + @service('data-sink/protocols/local-storage') settings; prepare(uri, data, assign) { const [providerName, pathname] = parts(uri); diff --git a/ui/packages/consul-ui/app/services/data-source/service.js b/ui/packages/consul-ui/app/services/data-source/service.js index 7e8b2a95e..d37b60b65 100644 --- a/ui/packages/consul-ui/app/services/data-source/service.js +++ b/ui/packages/consul-ui/app/services/data-source/service.js @@ -1,4 +1,5 @@ import Service, { inject as service } from '@ember/service'; +import { runInDebug } from '@ember/debug'; import { proxy } from 'consul-ui/utils/dom/event-source'; import { schedule } from '@ember/runloop'; @@ -12,18 +13,19 @@ let cache = null; let sources = null; // keeps a count of currently in use EventSources let usage = null; +class URI { + constructor(uri) { + this.uri = uri; + } + toString() { + return this.uri; + } +} export default class DataSourceService extends Service { - @service('dom') - dom; - - @service('encoder') - encoder; - - @service('data-source/protocols/http') - consul; - - @service('data-source/protocols/local-storage') - settings; + @service('dom') dom; + @service('encoder') encoder; + @service('data-source/protocols/http') consul; + @service('data-source/protocols/local-storage') settings; init() { super.init(...arguments); @@ -86,10 +88,22 @@ export default class DataSourceService extends Service { return source; } + uri(str) { + return new URI(str); + } + open(uri, ref, open = false) { - if (typeof uri !== 'string') { + if (!(uri instanceof URI) && typeof uri !== 'string') { return this.unwrap(uri, ref); } + runInDebug( + _ => { + if(!(uri instanceof URI)) { + console.error(new Error(`DataSource '${uri}' does not use the uri helper. Please ensure you use the uri helper to ensure correct encoding`)) + } + } + ); + uri = uri.toString(); let source; // Check the cache for an EventSource that is already being used // for this uri. If we don't have one, set one up. diff --git a/ui/packages/consul-ui/app/templates/application.hbs b/ui/packages/consul-ui/app/templates/application.hbs index a732cffd9..68bfdba6e 100644 --- a/ui/packages/consul-ui/app/templates/application.hbs +++ b/ui/packages/consul-ui/app/templates/application.hbs @@ -19,7 +19,7 @@ as |route|> {{! Tell CSS about our theme }} {{#each-in source.data as |key value|}} {{#if (and value (contains key (array "color-scheme" "contrast")))}} @@ -31,7 +31,7 @@ as |source|> {{! If ACLs are enabled try get a token }} {{#if (can "use acls")}} {{/if}} diff --git a/ui/packages/consul-ui/app/templates/dc/nodes/show/sessions.hbs b/ui/packages/consul-ui/app/templates/dc/nodes/show/sessions.hbs index 0bc99bdda..72dcb360c 100644 --- a/ui/packages/consul-ui/app/templates/dc/nodes/show/sessions.hbs +++ b/ui/packages/consul-ui/app/templates/dc/nodes/show/sessions.hbs @@ -1,8 +1,7 @@ -