Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ui: Fix URL params decoding #11931

Merged
merged 3 commits into from
Jan 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .changelog/11931.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:bug
ui: Fixes a bug with URL decoding within KV area
```
30 changes: 7 additions & 23 deletions ui/packages/consul-ui/app/routing/route.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,14 @@ import Route from '@ember/routing/route';
import { get, setProperties, action } from '@ember/object';
import { inject as service } from '@ember/service';

// paramsFor
import { routes } from 'consul-ui/router';
import wildcard from 'consul-ui/utils/routing/wildcard';

const isWildcard = wildcard(routes);

export default class BaseRoute extends Route {
@service('container') container;
@service('env') env;
@service('repository/permission') permissions;
@service('router') router;
@service('routlet') routlet;

_setRouteName() {
super._setRouteName(...arguments);
Expand Down Expand Up @@ -114,27 +111,14 @@ export default class BaseRoute extends Route {
}

/**
* Adds urldecoding to any wildcard route `params` passed into ember `model`
* hooks, plus of course anywhere else where `paramsFor` is used. This means
* the entire ember app is now changed so that all paramsFor calls returns
* urldecoded params instead of raw ones.
* For example we use this largely for URLs for the KV store:
* /kv/*key > /ui/kv/%25-kv-name/%25-here > key = '%-kv-name/%-here'
* Normalizes any params passed into ember `model` hooks, plus of course
* anywhere else where `paramsFor` is used. This means the entire ember app
* is now changed so that all paramsFor calls returns normalized params
* instead of raw ones. For example we use this largely for URLs for the KV
* store: /kv/*key > /ui/kv/%25-kv-name/%25-here > key = '%-kv-name/%-here'
*/
paramsFor(name) {
const params = super.paramsFor(...arguments);
if (isWildcard(this.routeName)) {
return Object.keys(params).reduce(function(prev, item) {
if (typeof params[item] !== 'undefined') {
prev[item] = decodeURIComponent(params[item]);
} else {
prev[item] = params[item];
}
return prev;
}, {});
} else {
return params;
}
return this.routlet.normalizeParamsFor(this.routeName, super.paramsFor(...arguments));
}

@action
Expand Down
29 changes: 25 additions & 4 deletions ui/packages/consul-ui/app/services/routlet.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import Service, { inject as service } from '@ember/service';
import { schedule } from '@ember/runloop';

import wildcard from 'consul-ui/utils/routing/wildcard';
import { routes } from 'consul-ui/router';

const isWildcard = wildcard(routes);

class Outlets {
constructor() {
this.map = new Map();
Expand Down Expand Up @@ -87,6 +92,24 @@ export default class RoutletService extends Service {
return {};
}

/**
* Adds urldecoding to any wildcard route `params`
*/
normalizeParamsFor(name, params = {}) {
if (isWildcard(name)) {
return Object.keys(params).reduce(function(prev, item) {
if (typeof params[item] !== 'undefined') {
prev[item] = decodeURIComponent(params[item]);
} else {
prev[item] = params[item];
}
return prev;
}, {});
} else {
return params;
}
}

paramsFor(name) {
let outletParams = {};
const outlet = outlets.get(name);
Expand All @@ -102,16 +125,14 @@ export default class RoutletService extends Service {
// of the specified params with the values specified
let current = route;
let parent;
let routeParams = {
...current.params,
};
let routeParams = this.normalizeParamsFor(name, current.params);
// TODO: Not entirely sure whether we are ok exposing queryParams here
// seeing as accessing them from here means you can get them but not set
// them as yet
// let queryParams = {};
while ((parent = current.parent)) {
routeParams = {
...parent.params,
...this.normalizeParamsFor(parent.name, parent.params),
...routeParams,
};
// queryParams = {
Expand Down
2 changes: 1 addition & 1 deletion ui/packages/consul-ui/app/templates/dc/kv/edit.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ as |parts|}}
</BlockSlot>

<BlockSlot @name="header">
<h1>
<h1 data-test-kv-key={{item.Key}}>
{{#if (and item.Key (not-eq item.Key parentKey))}}
<route.Title @title="Edit Key / Value" @render={{false}} />
{{left-trim item.Key parentKey}}
Expand Down
19 changes: 17 additions & 2 deletions ui/packages/consul-ui/tests/acceptance/dc/kvs/edit.feature
Original file line number Diff line number Diff line change
@@ -1,6 +1,19 @@
@setupApplicationTest
Feature: dc / kvs / edit: KV Viewing
Scenario:
Scenario: Viewing a KV with a URL unsafe character
Given 1 datacenter model with the value "datacenter"
And 1 kv model from yaml
---
Key: "@key"
---
When I visit the kv page for yaml
---
dc: datacenter
kv: "@key"
---
Then the url should be /datacenter/kv/%40key/edit
And I see Key on the kv like "@key"
Scenario: Viewing a Session attached to a KV
Given 1 datacenter model with the value "datacenter"
And 1 kv model from yaml
---
Expand All @@ -14,7 +27,9 @@ Feature: dc / kvs / edit: KV Viewing
---
Then the url should be /datacenter/kv/key/edit
And I see ID on the session like "session-id"
Given 1 kv model from yaml
Scenario: Viewing a Session attached to a KV
Given 1 datacenter model with the value "datacenter"
And 1 kv model from yaml
---
Key: another-key
Session: ~
Expand Down
3 changes: 3 additions & 0 deletions ui/packages/consul-ui/tests/pages/dc/kv/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ export default function(visitable, attribute, present, submitable, deletable, ca
...submitable({}, 'main'),
...cancelable(),
...deletable(),
kv: {
Key: attribute('data-test-kv-key', '[data-test-kv-key]')
},
session: {
warning: present('[data-test-session-warning]'),
ID: attribute('data-test-session', '[data-test-session]'),
Expand Down