diff --git a/app-modules/in-app-communication/resources/js/TipTap/Extentions/SafeLink.js b/app-modules/in-app-communication/resources/js/TipTap/Extentions/SafeLink.js new file mode 100644 index 0000000000..7e617ef9f8 --- /dev/null +++ b/app-modules/in-app-communication/resources/js/TipTap/Extentions/SafeLink.js @@ -0,0 +1,55 @@ +/* + + + Copyright © 2016-2024, Canyon GBS LLC. All rights reserved. + + Advising App™ is licensed under the Elastic License 2.0. For more details, + see https://github.com/canyongbs/advisingapp/blob/main/LICENSE. + + Notice: + + - You may not provide the software to third parties as a hosted or managed + service, where the service provides users with access to any substantial set of + the features or functionality of the software. + - You may not move, change, disable, or circumvent the license key functionality + in the software, and you may not remove or obscure any functionality in the + software that is protected by the license key. + - You may not alter, remove, or obscure any licensing, copyright, or other notices + of the licensor in the software. Any use of the licensor’s trademarks is subject + to applicable law. + - Canyon GBS LLC respects the intellectual property rights of others and expects the + same in return. Canyon GBS™ and Advising App™ are registered trademarks of + Canyon GBS LLC, and we are committed to enforcing and protecting our trademarks + vigorously. + - The software solution, including services, infrastructure, and code, is offered as a + Software as a Service (SaaS) by Canyon GBS LLC. + - Use of this software implies agreement to the license terms and conditions as stated + in the Elastic License 2.0. + + For more information or inquiries please visit our website at + https://www.canyongbs.com or contact us via email at legal@canyongbs.com. + + +*/ +import Link from '@tiptap/extension-link'; +import { mergeAttributes } from '@tiptap/core'; + +export const SafeLink = Link.extend({ + renderHTML({ HTMLAttributes }) { + // This is directly pulled from the Link extension - leave as is. + // eslint-disable-next-line no-script-url + if (HTMLAttributes.href?.startsWith('javascript:')) { + return [ + 'button', + mergeAttributes(this.options.HTMLAttributes, { ...HTMLAttributes, 'data-safe-link': 'true', href: '' }), + 0, + ]; + } + + return [ + 'button', + mergeAttributes(this.options.HTMLAttributes, { ...HTMLAttributes, 'data-safe-link': 'true' }), + 0, + ]; + }, +}); diff --git a/app-modules/in-app-communication/resources/js/userToUserChat.js b/app-modules/in-app-communication/resources/js/userToUserChat.js index 65ccff5d9e..53e5dc2a85 100644 --- a/app-modules/in-app-communication/resources/js/userToUserChat.js +++ b/app-modules/in-app-communication/resources/js/userToUserChat.js @@ -36,7 +36,7 @@ document.addEventListener('alpine:init', () => { const { generateHTML } = require('@tiptap/html'); const { Color } = require('@tiptap/extension-color'); const { Editor } = require('@tiptap/core'); - const { Link } = require('@tiptap/extension-link'); + const { SafeLink } = require('./TipTap/Extentions/SafeLink'); const { Mention } = require('./TipTap/Extentions/Mention'); const { Placeholder } = require('@tiptap/extension-placeholder'); const { StarterKit } = require('@tiptap/starter-kit'); @@ -240,6 +240,17 @@ document.addEventListener('alpine:init', () => { window.addEventListener('chatTyping', () => { this.conversation?.typing(); }); + + window.addEventListener('click', (event) => { + const target = event.target; + + if (target.matches('[data-safe-link]')) { + this.openConfirmationModal(target.getAttribute('href')); + } + }); + }, + openConfirmationModal(href) { + this.$dispatch('open-modal', { id: 'confirmSafeLink', href: href }); }, async getMessages() { this.loadingMessage = 'Loading messages…'; @@ -314,11 +325,9 @@ document.addEventListener('alpine:init', () => { generateHTML: (content) => { return generateHTML(content, [ Color, - Link.configure({ + SafeLink.configure({ openOnClick: false, HTMLAttributes: { - target: '_blank', - rel: 'noopener noreferrer nofollow', class: 'underline font-medium text-primary-600 dark:text-primary-500', }, }), @@ -351,11 +360,9 @@ document.addEventListener('alpine:init', () => { element: this.$refs.element, extensions: [ Color, - Link.configure({ + SafeLink.configure({ openOnClick: false, HTMLAttributes: { - target: '_blank', - rel: 'noopener noreferrer nofollow', class: 'underline font-medium text-primary-600 dark:text-primary-500', }, }), diff --git a/app-modules/in-app-communication/resources/views/filament/pages/user-chat.blade.php b/app-modules/in-app-communication/resources/views/filament/pages/user-chat.blade.php index 041fdbe9b6..68a96a98cc 100644 --- a/app-modules/in-app-communication/resources/views/filament/pages/user-chat.blade.php +++ b/app-modules/in-app-communication/resources/views/filament/pages/user-chat.blade.php @@ -612,4 +612,55 @@ class="h-2 w-2 animate-bounce rounded-full bg-primary-500 text-primary-500 anima } + + + +

Link confirmation

+
+ + +
+ You are about to open another browser tab and visit: + +
+
+ + +
+ + Cancel + + + + Continue + + +
+
+
+