diff --git a/.changelog/11117.txt b/.changelog/11117.txt
new file mode 100644
index 0000000000..6d18e5abd6
--- /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 c2cc07b6fd..afeeba0fd3 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 5c872001ae..559eff6bbc 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 c550534956..fcbeeaa4f1 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 83ad29ad95..b0c2a5f9c3 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 98d0a96305..d47314aa6d 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 8c3667ea11..7c0692c1c8 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 31b051252f..6e64c558c9 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 7e8b2a95ee..d37b60b655 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 a732cffd9b..68bfdba6eb 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 0bc99bddad..72dcb360cb 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 @@
-