@gitlab/ui 66.36.1 → 67.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +21 -0
- package/dist/components/base/filtered_search/filtered_search.js +3 -4
- package/dist/components/experimental/duo/chat/components/duo_chat_message/duo_chat_message.js +4 -1
- package/dist/directives/safe_html/constants.js +2 -1
- package/dist/directives/safe_html/safe_html.js +3 -2
- package/dist/tokens/css/tokens.css +1 -1
- package/dist/tokens/css/tokens.dark.css +1 -1
- package/dist/tokens/js/tokens.dark.js +1 -1
- package/dist/tokens/js/tokens.js +1 -1
- package/dist/tokens/scss/_tokens.dark.scss +1 -1
- package/dist/tokens/scss/_tokens.scss +1 -1
- package/package.json +1 -1
- package/src/components/base/filtered_search/filtered_search.vue +2 -4
- package/src/components/experimental/duo/chat/components/duo_chat_message/duo_chat_message.spec.js +5 -0
- package/src/components/experimental/duo/chat/components/duo_chat_message/duo_chat_message.vue +4 -1
- package/src/directives/safe_html/constants.js +2 -0
- package/src/directives/safe_html/safe_html.js +3 -2
- package/src/directives/safe_html/safe_html.spec.js +15 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,24 @@
|
|
|
1
|
+
# [67.0.0](https://gitlab.com/gitlab-org/gitlab-ui/compare/v66.37.0...v67.0.0) (2023-10-27)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* **SafeHtml:** disallow potentially dangerous tags ([25926ab](https://gitlab.com/gitlab-org/gitlab-ui/commit/25926ab418ffbbbe657a6a1485d01c13368e2a67))
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### BREAKING CHANGES
|
|
10
|
+
|
|
11
|
+
* **SafeHtml:** This change improves safe-html defense
|
|
12
|
+
by adding style, mystlye and form tags to the forbidden
|
|
13
|
+
list.
|
|
14
|
+
|
|
15
|
+
# [66.37.0](https://gitlab.com/gitlab-org/gitlab-ui/compare/v66.36.1...v66.37.0) (2023-10-25)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
### Features
|
|
19
|
+
|
|
20
|
+
* **GlDuoChatMessage:** do not strip out copy-code ([14782a5](https://gitlab.com/gitlab-org/gitlab-ui/commit/14782a5d60a8e48dffb60fa120bddc61285d950a))
|
|
21
|
+
|
|
1
22
|
## [66.36.1](https://gitlab.com/gitlab-org/gitlab-ui/compare/v66.36.0...v66.36.1) (2023-10-24)
|
|
2
23
|
|
|
3
24
|
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import isEqual from 'lodash/isEqual';
|
|
2
2
|
import cloneDeep from 'lodash/cloneDeep';
|
|
3
|
-
import
|
|
4
|
-
import Vue from 'vue';
|
|
3
|
+
import { PortalTarget } from 'portal-vue';
|
|
5
4
|
import { GlTooltipDirective } from '../../../directives/tooltip';
|
|
6
5
|
import GlIcon from '../icon/icon';
|
|
7
6
|
import GlSearchBoxByClick from '../search_box_by_click/search_box_by_click';
|
|
@@ -9,7 +8,6 @@ import GlFilteredSearchTerm from './filtered_search_term';
|
|
|
9
8
|
import { termTokenDefinition, createTerm, needDenormalization, denormalizeTokens, isEmptyTerm, INTENT_ACTIVATE_PREVIOUS, ensureTokenId, normalizeTokens } from './filtered_search_utils';
|
|
10
9
|
import __vue_normalize__ from 'vue-runtime-helpers/dist/normalize-component.js';
|
|
11
10
|
|
|
12
|
-
Vue.use(PortalVue);
|
|
13
11
|
let portalUuid = 0;
|
|
14
12
|
function initialState() {
|
|
15
13
|
return [createTerm()];
|
|
@@ -18,7 +16,8 @@ var script = {
|
|
|
18
16
|
name: 'GlFilteredSearch',
|
|
19
17
|
components: {
|
|
20
18
|
GlSearchBoxByClick,
|
|
21
|
-
GlIcon
|
|
19
|
+
GlIcon,
|
|
20
|
+
PortalTarget
|
|
22
21
|
},
|
|
23
22
|
directives: {
|
|
24
23
|
GlTooltip: GlTooltipDirective
|
package/dist/components/experimental/duo/chat/components/duo_chat_message/duo_chat_message.js
CHANGED
|
@@ -14,6 +14,9 @@ const concatIndicesUntilEmpty = arr => {
|
|
|
14
14
|
};
|
|
15
15
|
var script = {
|
|
16
16
|
name: 'GlDuoChatMessage',
|
|
17
|
+
safeHtmlConfigExtension: {
|
|
18
|
+
ADD_TAGS: ['copy-code']
|
|
19
|
+
},
|
|
17
20
|
components: {
|
|
18
21
|
DocumentationSources,
|
|
19
22
|
GlDuoUserFeedback
|
|
@@ -102,7 +105,7 @@ var __vue_render__ = function () {var _vm=this;var _h=_vm.$createElement;var _c=
|
|
|
102
105
|
'gl-ml-auto gl-bg-blue-100 gl-text-blue-900 gl-rounded-bottom-right-none': _vm.isUserMessage,
|
|
103
106
|
'gl-rounded-bottom-left-none gl-text-gray-900 gl-bg-white gl-border-1 gl-border-solid gl-border-gray-50':
|
|
104
107
|
_vm.isAssistantMessage,
|
|
105
|
-
}},[_c('div',{directives:[{name:"safe-html",rawName:"v-safe-html",value:(_vm.messageContent),expression:"messageContent"}],ref:"content"}),_vm._v(" "),(_vm.isAssistantMessage)?[(_vm.sources)?_c('documentation-sources',{attrs:{"sources":_vm.sources}}):_vm._e(),_vm._v(" "),_c('div',{staticClass:"gl-display-flex gl-align-items-flex-end gl-mt-4"},[_c('gl-duo-user-feedback',{on:{"feedback":function($event){return _vm.$emit('track-feedback', $event)}}})],1)]:_vm._e()],2)};
|
|
108
|
+
}},[_c('div',{directives:[{name:"safe-html",rawName:"v-safe-html:[$options.safeHtmlConfigExtension]",value:(_vm.messageContent),expression:"messageContent",arg:_vm.$options.safeHtmlConfigExtension}],ref:"content"}),_vm._v(" "),(_vm.isAssistantMessage)?[(_vm.sources)?_c('documentation-sources',{attrs:{"sources":_vm.sources}}):_vm._e(),_vm._v(" "),_c('div',{staticClass:"gl-display-flex gl-align-items-flex-end gl-mt-4"},[_c('gl-duo-user-feedback',{on:{"feedback":function($event){return _vm.$emit('track-feedback', $event)}}})],1)]:_vm._e()],2)};
|
|
106
109
|
var __vue_staticRenderFns__ = [];
|
|
107
110
|
|
|
108
111
|
/* style */
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// See https://gitlab.com/gitlab-org/gitlab-ui/-/issues/1421#note_617098438
|
|
2
2
|
// for more details
|
|
3
3
|
const forbiddenDataAttrs = ['data-remote', 'data-url', 'data-type', 'data-method', 'data-disable-with', 'data-disabled', 'data-disable', 'data-turbo'];
|
|
4
|
+
const forbiddenTags = ['style', 'mstyle', 'form'];
|
|
4
5
|
|
|
5
|
-
export { forbiddenDataAttrs };
|
|
6
|
+
export { forbiddenDataAttrs, forbiddenTags };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import DOMPurify from 'dompurify';
|
|
2
|
-
import { forbiddenDataAttrs } from './constants';
|
|
2
|
+
import { forbiddenDataAttrs, forbiddenTags } from './constants';
|
|
3
3
|
|
|
4
4
|
const {
|
|
5
5
|
sanitize
|
|
@@ -13,7 +13,8 @@ const {
|
|
|
13
13
|
const DEFAULT_CONFIG = {
|
|
14
14
|
RETURN_DOM_FRAGMENT: true,
|
|
15
15
|
ALLOW_UNKNOWN_PROTOCOLS: true,
|
|
16
|
-
FORBID_ATTR:
|
|
16
|
+
FORBID_ATTR: forbiddenDataAttrs,
|
|
17
|
+
FORBID_TAGS: forbiddenTags
|
|
17
18
|
};
|
|
18
19
|
const transform = (el, binding) => {
|
|
19
20
|
if (binding.oldValue !== binding.value) {
|
package/dist/tokens/js/tokens.js
CHANGED
package/package.json
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
<script>
|
|
2
2
|
import isEqual from 'lodash/isEqual';
|
|
3
3
|
import cloneDeep from 'lodash/cloneDeep';
|
|
4
|
-
import
|
|
5
|
-
import Vue from 'vue';
|
|
4
|
+
import { PortalTarget } from 'portal-vue';
|
|
6
5
|
import { GlTooltipDirective } from '../../../directives/tooltip';
|
|
7
6
|
import GlIcon from '../icon/icon.vue';
|
|
8
7
|
import GlSearchBoxByClick from '../search_box_by_click/search_box_by_click.vue';
|
|
@@ -18,8 +17,6 @@ import {
|
|
|
18
17
|
termTokenDefinition,
|
|
19
18
|
} from './filtered_search_utils';
|
|
20
19
|
|
|
21
|
-
Vue.use(PortalVue);
|
|
22
|
-
|
|
23
20
|
let portalUuid = 0;
|
|
24
21
|
|
|
25
22
|
function initialState() {
|
|
@@ -31,6 +28,7 @@ export default {
|
|
|
31
28
|
components: {
|
|
32
29
|
GlSearchBoxByClick,
|
|
33
30
|
GlIcon,
|
|
31
|
+
PortalTarget,
|
|
34
32
|
},
|
|
35
33
|
directives: { GlTooltip: GlTooltipDirective },
|
|
36
34
|
provide() {
|
package/src/components/experimental/duo/chat/components/duo_chat_message/duo_chat_message.spec.js
CHANGED
|
@@ -15,6 +15,7 @@ describe('DuoChatMessage', () => {
|
|
|
15
15
|
const findContent = () => wrapper.findComponent({ ref: 'content' });
|
|
16
16
|
const findDocumentSources = () => wrapper.findComponent(DocumentationSources);
|
|
17
17
|
const findUserFeedback = () => wrapper.findComponent(GlDuoUserFeedback);
|
|
18
|
+
const findCopyCodeButton = () => wrapper.find('copy-code');
|
|
18
19
|
const mockMarkdownContent = 'foo **bar**';
|
|
19
20
|
|
|
20
21
|
let renderMarkdown;
|
|
@@ -106,6 +107,10 @@ describe('DuoChatMessage', () => {
|
|
|
106
107
|
findUserFeedback().vm.$emit('feedback', 'foo');
|
|
107
108
|
expect(wrapper.emitted('track-feedback')).toEqual([['foo']]);
|
|
108
109
|
});
|
|
110
|
+
|
|
111
|
+
it('does not strip out the <copy-code/> element from HTML output', () => {
|
|
112
|
+
expect(findCopyCodeButton().exists()).toBe(true);
|
|
113
|
+
});
|
|
109
114
|
});
|
|
110
115
|
|
|
111
116
|
describe('message output', () => {
|
package/src/components/experimental/duo/chat/components/duo_chat_message/duo_chat_message.vue
CHANGED
|
@@ -15,6 +15,9 @@ const concatIndicesUntilEmpty = (arr) => {
|
|
|
15
15
|
|
|
16
16
|
export default {
|
|
17
17
|
name: 'GlDuoChatMessage',
|
|
18
|
+
safeHtmlConfigExtension: {
|
|
19
|
+
ADD_TAGS: ['copy-code'],
|
|
20
|
+
},
|
|
18
21
|
components: {
|
|
19
22
|
DocumentationSources,
|
|
20
23
|
GlDuoUserFeedback,
|
|
@@ -102,7 +105,7 @@ export default {
|
|
|
102
105
|
isAssistantMessage,
|
|
103
106
|
}"
|
|
104
107
|
>
|
|
105
|
-
<div ref="content" v-safe-html="messageContent"></div>
|
|
108
|
+
<div ref="content" v-safe-html:[$options.safeHtmlConfigExtension]="messageContent"></div>
|
|
106
109
|
|
|
107
110
|
<template v-if="isAssistantMessage">
|
|
108
111
|
<documentation-sources v-if="sources" :sources="sources" />
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import DOMPurify from 'dompurify';
|
|
2
|
-
import { forbiddenDataAttrs } from './constants';
|
|
2
|
+
import { forbiddenDataAttrs, forbiddenTags } from './constants';
|
|
3
3
|
|
|
4
4
|
const { sanitize } = DOMPurify;
|
|
5
5
|
|
|
@@ -11,7 +11,8 @@ const { sanitize } = DOMPurify;
|
|
|
11
11
|
const DEFAULT_CONFIG = {
|
|
12
12
|
RETURN_DOM_FRAGMENT: true,
|
|
13
13
|
ALLOW_UNKNOWN_PROTOCOLS: true,
|
|
14
|
-
FORBID_ATTR:
|
|
14
|
+
FORBID_ATTR: forbiddenDataAttrs,
|
|
15
|
+
FORBID_TAGS: forbiddenTags,
|
|
15
16
|
};
|
|
16
17
|
|
|
17
18
|
const transform = (el, binding) => {
|
|
@@ -49,6 +49,21 @@ describe('safe html directive', () => {
|
|
|
49
49
|
expect(wrapper.html()).toEqual('<div><a>click here</a></div>');
|
|
50
50
|
});
|
|
51
51
|
|
|
52
|
+
it('should remove style tags', () => {
|
|
53
|
+
createComponent({ html: '<style>p {width:50%;}</style>' });
|
|
54
|
+
expect(wrapper.html()).toEqual('<div></div>');
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('should remove mstyle tags', () => {
|
|
58
|
+
createComponent({ html: '<math><mstyle displaystyle="true"></mstyle></math>' });
|
|
59
|
+
expect(wrapper.html()).toEqual('<div><math></math></div>');
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('should remove form tags', () => {
|
|
63
|
+
createComponent({ html: '<form method="post" action="path"></form>' });
|
|
64
|
+
expect(wrapper.html()).toEqual('<div></div>');
|
|
65
|
+
});
|
|
66
|
+
|
|
52
67
|
it('should remove any existing children', () => {
|
|
53
68
|
createComponent({
|
|
54
69
|
template: `<div v-safe-html="rawHtml">foo <i>bar</i></div>`,
|