@chat21/chat21-web-widget 5.1.2-rc6 → 5.1.4
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 +19 -0
- package/deploy_amazon_prod.sh +20 -6
- package/package.json +1 -1
- package/src/app/component/conversation-detail/conversation/conversation.component.ts +3 -1
- package/src/app/component/conversation-detail/conversation-footer/conversation-footer.component.ts +6 -6
- package/src/app/component/eyeeye-catcher-card/eyeeye-catcher-card.component.ts +35 -13
- package/src/app/component/message/avatar/avatar.component.scss +1 -1
- package/src/app/component/message/buttons/action-button/action-button.component.scss +1 -1
- package/src/app/component/message/buttons/link-button/link-button.component.scss +1 -1
- package/src/app/component/message/buttons/text-button/text-button.component.scss +1 -1
- package/src/app/pipe/marked.pipe.ts +120 -1
- package/src/app/utils/globals.ts +1 -1
- package/src/app/utils/utils.ts +69 -4
- package/src/chat21-core/providers/firebase/firebase-conversation-handler.ts +2 -2
- package/src/chat21-core/providers/mqtt/mqtt-conversation-handler.ts +3 -3
- package/src/chat21-core/utils/utils.ts +4 -0
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,23 @@
|
|
|
7
7
|
*Tiledesk SRL*
|
|
8
8
|
|
|
9
9
|
|
|
10
|
+
# 5.1.4
|
|
11
|
+
|
|
12
|
+
# 5.1.3-rc1
|
|
13
|
+
- **changed** Check if the uploaded file extension directly matches one of those allowed in the control panel (e.g. .xls)
|
|
14
|
+
|
|
15
|
+
# 5.1.3
|
|
16
|
+
|
|
17
|
+
# 5.1.2-rc9
|
|
18
|
+
- **added** .xls and .xlsx to file Upload Accept
|
|
19
|
+
|
|
20
|
+
# 5.1.2-rc8
|
|
21
|
+
- **bug-fixed**: css margin icon
|
|
22
|
+
- **added**: added text verification to delete dangerous patterns
|
|
23
|
+
|
|
24
|
+
# 5.1.2-rc7
|
|
25
|
+
- **bug-fixed**: ctest button color (#ffffff)
|
|
26
|
+
|
|
10
27
|
# 5.1.2-rc6
|
|
11
28
|
- **bug-fixed**: cannot upload xlsx files
|
|
12
29
|
|
|
@@ -40,6 +57,8 @@
|
|
|
40
57
|
# 5.1.1-rc1
|
|
41
58
|
- **bug-fixed**: marked pipe not renders urls
|
|
42
59
|
|
|
60
|
+
# 5.1.0
|
|
61
|
+
|
|
43
62
|
# 5.1.0-rc34
|
|
44
63
|
- **bug-fixed**: css fixed carousel
|
|
45
64
|
|
package/deploy_amazon_prod.sh
CHANGED
|
@@ -2,8 +2,18 @@
|
|
|
2
2
|
version=`node -e 'console.log(require("./package.json").version)'`
|
|
3
3
|
echo "version $version"
|
|
4
4
|
|
|
5
|
+
npm i
|
|
6
|
+
|
|
7
|
+
cp src/environments/real_data/environment.prod.ts src/environments/environment.prod.ts
|
|
8
|
+
|
|
5
9
|
# --build-optimizer=false if localstorage is disabled (webview) appears https://github.com/firebase/angularfire/issues/970
|
|
6
10
|
ng build --configuration="prod" --aot=true
|
|
11
|
+
##--base-href='./v5/' --output-hashing none
|
|
12
|
+
|
|
13
|
+
### SET HASHING : START ###
|
|
14
|
+
cp ./src/launch_template.js ./dist/browser/launch.js
|
|
15
|
+
node ./src/build_launch.js
|
|
16
|
+
### SET HASHING : END ###
|
|
7
17
|
|
|
8
18
|
#### FIREBASE #####
|
|
9
19
|
# cd dist
|
|
@@ -13,15 +23,19 @@ ng build --configuration="prod" --aot=true
|
|
|
13
23
|
# cd ..
|
|
14
24
|
|
|
15
25
|
# #### MQTT #####
|
|
16
|
-
cd dist
|
|
26
|
+
cd dist/browser
|
|
17
27
|
# aws s3 sync . s3://tiledesk-widget/v5/latest/
|
|
18
|
-
aws s3 sync . s3://tiledesk-widget/v6/$version/ --cache-control max-age=
|
|
19
|
-
aws s3 sync . s3://tiledesk-widget/v6/ --cache-control
|
|
20
|
-
|
|
21
|
-
|
|
28
|
+
aws s3 sync . s3://tiledesk-widget/v6/$version/ --cache-control max-age=86400 --exclude='launch.js' #8days
|
|
29
|
+
aws s3 sync . s3://tiledesk-widget/v6/$version/ --cache-control "no-store,no-cache,private" --exclude='*' --include='launch.js'
|
|
30
|
+
aws s3 sync . s3://tiledesk-widget/v6/ --cache-control max-age=86400 --exclude='launch.js' #8days
|
|
31
|
+
aws s3 sync . s3://tiledesk-widget/v6/ --cache-control "no-store,no-cache,private" --exclude='*' --include='launch.js'
|
|
32
|
+
cd ../..
|
|
22
33
|
|
|
23
34
|
aws cloudfront create-invalidation --distribution-id E3EJDWEHY08CZZ --paths "/*"
|
|
35
|
+
|
|
36
|
+
git restore src/environments/environment.pre.ts
|
|
37
|
+
|
|
24
38
|
echo new version deployed $version on s3://tiledesk-widget/v5
|
|
25
39
|
echo available on https://s3.eu-west-1.amazonaws.com/tiledesk-widget/v5/index.html
|
|
26
40
|
echo https://widget.tiledesk.com/v5/index.html
|
|
27
|
-
echo https://widget.tiledesk.com/v5/$version/index.html
|
|
41
|
+
echo https://widget.tiledesk.com/v5/$version/index.html
|
package/package.json
CHANGED
|
@@ -1414,7 +1414,9 @@ export class ConversationComponent implements OnInit, AfterViewInit, OnChanges {
|
|
|
1414
1414
|
this.logger.log('[CONV-COMP] ----> FILE - (dragleave) drag ev ', event)
|
|
1415
1415
|
if (event.dataTransfer && event.dataTransfer.files) {
|
|
1416
1416
|
const files = event.dataTransfer.files;
|
|
1417
|
-
const
|
|
1417
|
+
const nameFile = files[0].name;
|
|
1418
|
+
const typeFile = files[0].type;
|
|
1419
|
+
const canUploadFile = checkAcceptedFile(nameFile, typeFile, this.g.fileUploadAccept)
|
|
1418
1420
|
if(!canUploadFile){
|
|
1419
1421
|
this.logger.error('[IMAGE-UPLOAD] detectFiles: can not upload current file type--> NOT ALLOWED', this.g.fileUploadAccept)
|
|
1420
1422
|
return;
|
package/src/app/component/conversation-detail/conversation-footer/conversation-footer.component.ts
CHANGED
|
@@ -138,19 +138,19 @@ export class ConversationFooterComponent implements OnInit, OnChanges {
|
|
|
138
138
|
|
|
139
139
|
const that = this;
|
|
140
140
|
if (event.target.files && event.target.files[0]) {
|
|
141
|
+
const nameFile = event.target.files[0].name;
|
|
142
|
+
const typeFile = event.target.files[0].type;
|
|
143
|
+
const size = event.target.files[0].size;
|
|
141
144
|
|
|
142
|
-
const canUploadFile = checkAcceptedFile(
|
|
145
|
+
const canUploadFile = checkAcceptedFile(nameFile, typeFile, this.fileUploadAccept)
|
|
143
146
|
if(!canUploadFile){
|
|
144
147
|
this.logger.error('[IMAGE-UPLOAD] detectFiles: can not upload current file type--> NOT ALLOWED', this.fileUploadAccept)
|
|
145
148
|
this.isFilePendingToUpload = false;
|
|
146
149
|
return;
|
|
147
150
|
}
|
|
148
|
-
|
|
149
|
-
const nameFile = event.target.files[0].name;
|
|
150
|
-
const typeFile = event.target.files[0].type;
|
|
151
|
-
const size = event.target.files[0].size
|
|
151
|
+
|
|
152
152
|
const reader = new FileReader();
|
|
153
|
-
that.logger.debug('[CONV-FOOTER] OK preload: ', nameFile, typeFile, reader);
|
|
153
|
+
// that.logger.debug('[CONV-FOOTER] OK preload: ', nameFile, typeFile, reader);
|
|
154
154
|
reader.addEventListener('load', function () {
|
|
155
155
|
that.logger.debug('[CONV-FOOTER] addEventListener load', reader.result);
|
|
156
156
|
that.isFileSelected = true;
|
|
@@ -90,23 +90,48 @@ export class EyeeyeCatcherCardComponent implements OnInit {
|
|
|
90
90
|
}
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
+
// checkIsEmoji() {
|
|
94
|
+
// let title = this.g.CALLOUT_TITLE_PLACEHOLDER.trim();
|
|
95
|
+
// if (this.g.calloutTitle && this.g.calloutTitle !== '') {
|
|
96
|
+
// title = this.g.calloutTitle.trim();
|
|
97
|
+
// }
|
|
98
|
+
// this.title = title;
|
|
99
|
+
// const regex = emojiRegex();
|
|
100
|
+
// let match: any;
|
|
101
|
+
// // this.logger.debug('[EYEEYE-CATCHER-CARD]-->regex, emojiRegex', regex, emojiRegex)
|
|
102
|
+
// while (match = regex.exec(title)) {
|
|
103
|
+
// const emoji = match[0];
|
|
104
|
+
// this.logger.debug('[EYEEYE-CATCHER-CARD]--> match', match)
|
|
105
|
+
// if (title.indexOf(emoji) === 0) {
|
|
106
|
+
// this.title = title.replace(emoji, '');
|
|
107
|
+
// this.emoticon = emoji;
|
|
108
|
+
// }
|
|
109
|
+
// break;
|
|
110
|
+
// }
|
|
111
|
+
// }
|
|
112
|
+
|
|
113
|
+
|
|
93
114
|
checkIsEmoji() {
|
|
94
115
|
let title = this.g.CALLOUT_TITLE_PLACEHOLDER.trim();
|
|
95
116
|
if (this.g.calloutTitle && this.g.calloutTitle !== '') {
|
|
96
117
|
title = this.g.calloutTitle.trim();
|
|
97
118
|
}
|
|
119
|
+
|
|
120
|
+
// Reset emoticon
|
|
121
|
+
this.emoticon = null;
|
|
98
122
|
this.title = title;
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
123
|
+
|
|
124
|
+
// Regex per emoji Unicode (compatibile)
|
|
125
|
+
const regex = /(?:[\u2700-\u27bf]|(?:\ud83c[\udde6-\uddff]){2}|[\ud800-\udbff][\udc00-\udfff]|[\u0023-\u0039]\ufe0f?\u20e3|\u3299|\u3297|\u303d|\u3030|\u24c2|\ud83c[\udd70-\udd71]|\ud83c[\udd7e-\udd7f]|\ud83c\udd8e|\ud83c[\udd91-\udd9a]|\ud83c[\udde6-\uddff]|\ud83c[\ude01-\ude02]|\ud83c\ude1a|\ud83c\ude2f|\ud83c[\ude32-\ude3a]|\ud83c[\ude50-\ude51]|\u203c|\u2049|[\u25aa-\u25ab]|\u25b6|\u25c0|[\u25fb-\u25fe]|\u00a9|\u00ae|\u2122|\u2139|\ud83c\udc04|[\u2600-\u26FF]|\u2b05|\u2b06|\u2b07|\u2b1b|\u2b1c|\u2b50|\u2b55|\u231a|\u231b|\u2328|\u23cf|[\u23e9-\u23f3]|[\u23f8-\u23fa]|\ud83c\udccf|\u2934|\u2935|[\u2190-\u21ff])/;
|
|
126
|
+
const match = title.match(regex);
|
|
127
|
+
|
|
128
|
+
if (match) {
|
|
103
129
|
const emoji = match[0];
|
|
104
|
-
this.logger.debug('[EYEEYE-CATCHER-CARD]-->
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
break;
|
|
130
|
+
this.logger.debug('[EYEEYE-CATCHER-CARD]--> emoji trovata:', emoji);
|
|
131
|
+
|
|
132
|
+
// Estrai la prima emoji trovata e rimuovila dal testo
|
|
133
|
+
this.title = title.replace(emoji, '').trim();
|
|
134
|
+
this.emoticon = emoji;
|
|
110
135
|
}
|
|
111
136
|
}
|
|
112
137
|
|
|
@@ -164,6 +189,3 @@ export class EyeeyeCatcherCardComponent implements OnInit {
|
|
|
164
189
|
}
|
|
165
190
|
|
|
166
191
|
|
|
167
|
-
export default function emojiRegex(): RegExp {
|
|
168
|
-
return /(?:\uD83C[\uDFFB-\uDFFF])|(?:[\u2700-\u27BF])|(?:\u24C2)|(?:[\u1F680-\u1F6FF])/g;
|
|
169
|
-
}
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
--font-family: #{var(--button-in-msg-font-family)};
|
|
10
10
|
--buttonBorderColor: #{var(--button-border-color)};
|
|
11
11
|
--buttonColor: #{var(--button-color)};
|
|
12
|
-
--buttonBackgroundColor: #{var(--button-background-color)};
|
|
12
|
+
--buttonBackgroundColor: #ffffff; //#{var(--button-background-color)};
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
.button-in-msg {
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
--font-family: #{var(--button-in-msg-font-family)};
|
|
10
10
|
--buttonBorderColor: #{var(--button-border-color)};
|
|
11
11
|
--buttonColor: #{var(--button-color)};
|
|
12
|
-
--buttonBackgroundColor: #{var(--button-background-color)};
|
|
12
|
+
--buttonBackgroundColor: #ffffff; //#{var(--button-background-color)};
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
--font-family: #{var(--button-in-msg-font-family)};
|
|
10
10
|
--buttonBorderColor: #{var(--button-border-color)};
|
|
11
11
|
// --buttonColor: #{var(--buttonColor)};
|
|
12
|
-
--buttonBackgroundColor: #{var(--button-background-color)};
|
|
12
|
+
--buttonBackgroundColor: #ffffff; //#{var(--button-background-color)};
|
|
13
13
|
--buttonColor: #{var(--button-color)};
|
|
14
14
|
}
|
|
15
15
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Pipe, PipeTransform } from '@angular/core';
|
|
2
2
|
import { marked } from 'marked';
|
|
3
|
+
import { BLOCKED_DOMAINS } from '../utils/utils';
|
|
3
4
|
|
|
4
5
|
|
|
5
6
|
@Pipe({
|
|
@@ -10,6 +11,55 @@ export class MarkedPipe implements PipeTransform {
|
|
|
10
11
|
transform(value: any): any {
|
|
11
12
|
const renderer = new marked.Renderer();
|
|
12
13
|
renderer.link = function({ href, title, tokens }) {
|
|
14
|
+
// Normalizza l'href per evitare falsi negativi
|
|
15
|
+
const normalized = (href || '').trim().toLowerCase();
|
|
16
|
+
// Pattern pericolosi da cercare nell'intero URL (non solo all'inizio)
|
|
17
|
+
const dangerousPatterns = [
|
|
18
|
+
/javascript:/i, // javascript: protocol
|
|
19
|
+
/data:/i, // data: protocol
|
|
20
|
+
/vbscript:/i, // vbscript: protocol
|
|
21
|
+
/on\w+\s*=/i, // event handlers (onclick, onload, etc.)
|
|
22
|
+
/alert\s*\(/i, // alert() function
|
|
23
|
+
/eval\s*\(/i, // eval() function
|
|
24
|
+
/document\./i, // document object access
|
|
25
|
+
/window\./i, // window object access
|
|
26
|
+
/\.appendChild\s*\(/i, // DOM manipulation
|
|
27
|
+
/\.createElement\s*\(/i, // DOM creation
|
|
28
|
+
/<script/i, // script tags
|
|
29
|
+
/<\/script>/i, // closing script tags
|
|
30
|
+
/function\s*\(/i, // function definitions
|
|
31
|
+
/\(function/i, // IIFE patterns
|
|
32
|
+
/setTimeout\s*\(/i, // setTimeout
|
|
33
|
+
/setInterval\s*\(/i, // setInterval
|
|
34
|
+
/location\./i, // location object manipulation
|
|
35
|
+
/history\./i, // history object manipulation
|
|
36
|
+
/localStorage\./i, // localStorage access
|
|
37
|
+
/sessionStorage\./i, // sessionStorage access
|
|
38
|
+
/cookie/i, // cookie manipulation
|
|
39
|
+
/fetch\s*\(/i, // fetch API
|
|
40
|
+
/XMLHttpRequest/i, // XHR
|
|
41
|
+
/FormData/i, // FormData
|
|
42
|
+
/Blob\s*\(/i, // Blob constructor
|
|
43
|
+
/FileReader/i, // FileReader
|
|
44
|
+
/crypto\./i, // crypto object
|
|
45
|
+
/btoa\s*\(/i, // base64 encoding
|
|
46
|
+
/atob\s*\(/i, // base64 decoding
|
|
47
|
+
/decodeURI/i, // URI decoding
|
|
48
|
+
/encodeURI/i, // URI encoding
|
|
49
|
+
/String\.fromCharCode/i, // character code conversion
|
|
50
|
+
/unescape\s*\(/i, // unescape function
|
|
51
|
+
/escape\s*\(/i // escape function
|
|
52
|
+
];
|
|
53
|
+
|
|
54
|
+
// Controlla se l'URL contiene pattern pericolosi
|
|
55
|
+
const isDangerous = dangerousPatterns.some(pattern => pattern.test(normalized));
|
|
56
|
+
if (isDangerous) {
|
|
57
|
+
// Ritorna solo il testo come stringa, niente <a>
|
|
58
|
+
return tokens ? tokens.map(token => token.raw).join('') : href || '';
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// tokens = this.cleanInput(href);
|
|
62
|
+
|
|
13
63
|
const text = tokens
|
|
14
64
|
? tokens.map(token => token.raw).join('')
|
|
15
65
|
: href; // fallback se tokens non c'è
|
|
@@ -17,7 +67,7 @@ export class MarkedPipe implements PipeTransform {
|
|
|
17
67
|
|
|
18
68
|
return `<a href="${href}" target="_blank" rel="noopener noreferrer">${text}</a>`;
|
|
19
69
|
};
|
|
20
|
-
|
|
70
|
+
|
|
21
71
|
marked.setOptions({
|
|
22
72
|
renderer,
|
|
23
73
|
gfm: true,
|
|
@@ -35,4 +85,73 @@ export class MarkedPipe implements PipeTransform {
|
|
|
35
85
|
return value;
|
|
36
86
|
}
|
|
37
87
|
|
|
88
|
+
|
|
89
|
+
private cleanInput(input: string): string {
|
|
90
|
+
if (!input) return '';
|
|
91
|
+
let cleaned = (input || '').trim().toLowerCase();
|
|
92
|
+
|
|
93
|
+
BLOCKED_DOMAINS.forEach(domain => {
|
|
94
|
+
const escapedDomain = domain.replace(/\./g, '\\.');
|
|
95
|
+
// Pattern che copre TUTTI i casi
|
|
96
|
+
const comprehensivePattern = new RegExp(
|
|
97
|
+
`(\\[([^\\]]*)\\]\\([^)]*(?:https?://)?(?:www\\.)?${escapedDomain}(?:/[^)]*)?\\))|((?:https?://)?(?:www\\.)?${escapedDomain}(?:/\\S*)?)`,
|
|
98
|
+
'gi'
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
cleaned = cleaned.replace(comprehensivePattern, (match, p1, p2, p3) => {
|
|
102
|
+
// Se è un link markdown [text](url), mantieni il testo
|
|
103
|
+
if (p2) return `${p2} 🔒`;
|
|
104
|
+
// Se è un URL diretto, sostituisci con dominio + 🔒
|
|
105
|
+
if (p3) return `${domain} 🔒`;
|
|
106
|
+
return match;
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
// Pattern che sostituisce i link pericolosi con solo il testo
|
|
113
|
+
const dangerousLinkPatterns = [
|
|
114
|
+
// Sostituisce [text](javascript:...) con "text"
|
|
115
|
+
/\[([^\]]*)\]\(javascript:[^)]*\)/gi,
|
|
116
|
+
/\[([^\]]*)\]\(data:[^)]*\)/gi,
|
|
117
|
+
/\[([^\]]*)\]\(vbscript:[^)]*\)/gi,
|
|
118
|
+
/\[([^\]]*)\]\([^)]*alert\([^)]*\)/gi
|
|
119
|
+
];
|
|
120
|
+
|
|
121
|
+
dangerousLinkPatterns.forEach(pattern => {
|
|
122
|
+
cleaned = cleaned.replace(pattern, '$1'); // $1 = il testo del link
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
// Pattern generali per sicurezza (rimuovono completamente)
|
|
126
|
+
const generalPatterns = [
|
|
127
|
+
/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,
|
|
128
|
+
/<script[^>]*>[\s\S]*?<\/script>/gi, // Script multi-linea
|
|
129
|
+
/<script[^>]*>.*?<\/script>/gi, // Script single-line
|
|
130
|
+
/<script[^>]*>/gi, // Solo tag di apertura
|
|
131
|
+
/<\/script>/gi, // Solo tag di chiusura
|
|
132
|
+
/javascript:/gi,
|
|
133
|
+
/vbscript:/gi,
|
|
134
|
+
/data:/gi,
|
|
135
|
+
/on\w+\s*=/gi,
|
|
136
|
+
/alert\(/gi,
|
|
137
|
+
/eval\(/gi,
|
|
138
|
+
/document\./gi,
|
|
139
|
+
/window\./gi,
|
|
140
|
+
/\(function\s*\(\)\s*\{/gi,
|
|
141
|
+
/\.appendChild\(/gi,
|
|
142
|
+
/\.createElement\(/gi,
|
|
143
|
+
/\.getElementsByTagName\(/gi,
|
|
144
|
+
|
|
145
|
+
// ✅ PATTERN PER FUNZIONI IIFE (Immediately Invoked Function Expression):
|
|
146
|
+
/\(function\s*\(\s*\)\s*\{[\s\S]*?\}\)\(\s*\)\s*;/gi,
|
|
147
|
+
/\(function\s*\(\)\s*\{/gi
|
|
148
|
+
];
|
|
149
|
+
|
|
150
|
+
generalPatterns.forEach(pattern => {
|
|
151
|
+
cleaned = cleaned.replace(pattern, '');
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
return cleaned;
|
|
155
|
+
}
|
|
156
|
+
|
|
38
157
|
}
|
package/src/app/utils/globals.ts
CHANGED
|
@@ -406,7 +406,7 @@ export class Globals {
|
|
|
406
406
|
/**enable user to set a telegram number to chat with */
|
|
407
407
|
this.telegramUsername = ''
|
|
408
408
|
/**enable auto disconnect from messaging after a defined amount of time (s)*/
|
|
409
|
-
this.fileUploadAccept =
|
|
409
|
+
this.fileUploadAccept = '';//image/*,.pdf,.txt,.mp3,.xls,.xlsx"
|
|
410
410
|
this.disconnetTime = 0
|
|
411
411
|
|
|
412
412
|
this.showWaitTime = true;
|
package/src/app/utils/utils.ts
CHANGED
|
@@ -379,17 +379,23 @@ export function getUnique(arr, comp) {
|
|
|
379
379
|
.filter(e => arr[e]).map(e => arr[e]);
|
|
380
380
|
}
|
|
381
381
|
|
|
382
|
-
export function checkAcceptedFile(fileType, fileUploadAccept
|
|
382
|
+
export function checkAcceptedFile(nameFile, fileType, fileUploadAccept): boolean {
|
|
383
|
+
console.log('checkAcceptedFile ------------>', fileType, fileUploadAccept);
|
|
383
384
|
|
|
385
|
+
const fileExtension = getFileExtension(nameFile);
|
|
386
|
+
console.log('[CONV-FOOTER] fileExtension: ', fileExtension);
|
|
387
|
+
|
|
384
388
|
if (fileUploadAccept === '*/*') {
|
|
385
|
-
return true
|
|
389
|
+
return true;
|
|
386
390
|
}
|
|
391
|
+
|
|
387
392
|
// Dividi la stringa fileUploadAccept in un array di tipi accettati
|
|
388
393
|
const acceptedTypes = fileUploadAccept.split(',');
|
|
389
394
|
|
|
390
395
|
// Verifica se il tipo di file è accettato
|
|
391
396
|
return acceptedTypes.some((accept) => {
|
|
392
397
|
accept = accept.trim();
|
|
398
|
+
|
|
393
399
|
// Controlla per i tipi MIME con wildcard, come image/*
|
|
394
400
|
if (accept.endsWith('/*')) {
|
|
395
401
|
const baseMimeType = fileType.split('/')[0]; // Ottieni la parte principale del MIME type
|
|
@@ -402,9 +408,39 @@ export function checkAcceptedFile(fileType, fileUploadAccept ): boolean{
|
|
|
402
408
|
}
|
|
403
409
|
|
|
404
410
|
// Controlla per le estensioni di file specifiche come .pdf o .txt
|
|
405
|
-
|
|
411
|
+
const expectedMimeType = getMimeTypeFromExtension(accept);
|
|
412
|
+
if (expectedMimeType && fileType === expectedMimeType) {
|
|
413
|
+
return true;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
// // Controlla se l'estensione del file corrisponde direttamente
|
|
417
|
+
// if (accept.startsWith('.') && fileExtension === accept.substring(1)) {
|
|
418
|
+
// return true;
|
|
419
|
+
// }
|
|
420
|
+
|
|
421
|
+
// Controlla se l'estensione del file corrisponde direttamente
|
|
422
|
+
// Dividi la stringa fileUploadAccept in un array di tipi accettati
|
|
423
|
+
const acceptedTypes = fileUploadAccept.split(',');
|
|
424
|
+
//verifica se l'estensione del file è accettata
|
|
425
|
+
if (acceptedTypes.includes(fileExtension)) {
|
|
426
|
+
return true;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
return false;
|
|
406
430
|
});
|
|
431
|
+
}
|
|
432
|
+
|
|
407
433
|
|
|
434
|
+
/**
|
|
435
|
+
* Estrae l'estensione del file dal nome
|
|
436
|
+
* @param filename Nome del file
|
|
437
|
+
* @returns Estensione in lowercase (es. 'xlsx', 'pdf', 'jpg')
|
|
438
|
+
*/
|
|
439
|
+
export function getFileExtension(filename: string): string {
|
|
440
|
+
if (!filename || filename.indexOf('.') === -1) {
|
|
441
|
+
return '';
|
|
442
|
+
}
|
|
443
|
+
return filename.split('.').pop()?.toLowerCase() || '';
|
|
408
444
|
}
|
|
409
445
|
|
|
410
446
|
function getMimeTypeFromExtension(extension: string): string {
|
|
@@ -420,8 +456,37 @@ function getMimeTypeFromExtension(extension: string): string {
|
|
|
420
456
|
'.docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
|
421
457
|
'.xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
|
422
458
|
'.xls': 'application/vnd.ms-excel',
|
|
423
|
-
'.wav'
|
|
459
|
+
'.wav': 'audio/wav'
|
|
424
460
|
// Aggiungi altri tipi MIME se necessario
|
|
425
461
|
};
|
|
426
462
|
return mimeTypes[extension] || '';
|
|
427
463
|
}
|
|
464
|
+
|
|
465
|
+
export const BLOCKED_DOMAINS = [
|
|
466
|
+
// DOMINI MALEVOLI NOTI
|
|
467
|
+
'attacker.me', 'evil.com', 'malicious.site', 'hacker.com', 'phishing.com',
|
|
468
|
+
'malware.com', 'ransomware.com', 'trojan.com', 'virus.com', 'spyware.com',
|
|
469
|
+
|
|
470
|
+
// DOMINI DI PHISHING
|
|
471
|
+
'phish.com', 'stealer.com', 'credential-thief.com', 'login-stealer.com',
|
|
472
|
+
'password-stealer.com', 'banking-phish.com', 'paypal-phish.com',
|
|
473
|
+
|
|
474
|
+
// DOMINI DI SPAM
|
|
475
|
+
'spam.com', 'spammer.com', 'bulk-email.com', 'unsolicited.com',
|
|
476
|
+
|
|
477
|
+
// DOMINI TRUFFA
|
|
478
|
+
'scam.com', 'fraud.com', 'fake.com', 'counterfeit.com', 'hoax.com',
|
|
479
|
+
|
|
480
|
+
// DOMINI EXPLOIT
|
|
481
|
+
'exploit.com', 'vulnerability.com', 'zero-day.com', 'payload.com',
|
|
482
|
+
'shellcode.com', 'backdoor.com', 'rootkit.com',
|
|
483
|
+
|
|
484
|
+
// DOMINI BOTNET
|
|
485
|
+
'botnet.com', 'zombie-pc.com', 'command-control.com', 'c2-server.com',
|
|
486
|
+
|
|
487
|
+
// DOMINI ADWARE/MALVERTISING
|
|
488
|
+
'adware.com', 'malvertising.com', 'popup-ads.com', 'unwanted-ads.com',
|
|
489
|
+
|
|
490
|
+
// DOMINI GENERICI PERICOLOSI
|
|
491
|
+
'danger.com', 'unsafe.com', 'insecure.com', 'threat.com', 'risk.com',
|
|
492
|
+
]
|
|
@@ -387,9 +387,9 @@ export class FirebaseConversationHandler extends ConversationHandlerService {
|
|
|
387
387
|
complement = INFO_SUPPORT_USER_ADDED_COMPLEMENT;
|
|
388
388
|
} else {
|
|
389
389
|
|
|
390
|
-
if (message.attributes.messagelabel.parameters.
|
|
390
|
+
if (message.attributes.messagelabel.parameters.firstname) {
|
|
391
391
|
// other user has been added to the group (and he has a fullname)
|
|
392
|
-
subject = message.attributes.messagelabel.parameters.
|
|
392
|
+
subject = message.attributes.messagelabel.parameters.firstname;
|
|
393
393
|
verb = INFO_SUPPORT_USER_ADDED_VERB;
|
|
394
394
|
complement = INFO_SUPPORT_USER_ADDED_COMPLEMENT;
|
|
395
395
|
} else {
|
|
@@ -382,14 +382,14 @@ export class MQTTConversationHandler extends ConversationHandlerService {
|
|
|
382
382
|
verb = INFO_SUPPORT_USER_ADDED_YOU_VERB;
|
|
383
383
|
complement = INFO_SUPPORT_USER_ADDED_COMPLEMENT;
|
|
384
384
|
} else {
|
|
385
|
-
if (message.attributes.messagelabel.parameters.
|
|
385
|
+
if (message.attributes.messagelabel.parameters.firstname) {
|
|
386
386
|
// other user has been added to the group (and he has a fullname)
|
|
387
|
-
subject = message.attributes.messagelabel.parameters.
|
|
387
|
+
subject = message.attributes.messagelabel.parameters.firstname;
|
|
388
388
|
verb = INFO_SUPPORT_USER_ADDED_VERB;
|
|
389
389
|
complement = INFO_SUPPORT_USER_ADDED_COMPLEMENT;
|
|
390
390
|
} else {
|
|
391
391
|
// other user has been added to the group (and he has not a fullname, so use hes useruid)
|
|
392
|
-
subject = message.attributes.messagelabel.parameters.
|
|
392
|
+
subject = message.attributes.messagelabel.parameters.firstname;
|
|
393
393
|
verb = INFO_SUPPORT_USER_ADDED_VERB;
|
|
394
394
|
complement = INFO_SUPPORT_USER_ADDED_COMPLEMENT;
|
|
395
395
|
}
|
|
@@ -620,6 +620,10 @@ function componentFromStr(numStr, percent) {
|
|
|
620
620
|
export function isAllowedUrlInText(text: string, allowedUrls: string[]) {
|
|
621
621
|
const urlsInMessage = extractUrls(text);
|
|
622
622
|
|
|
623
|
+
if (urlsInMessage.length === 0) {
|
|
624
|
+
return true; // Nessun URL => testo ammesso
|
|
625
|
+
}
|
|
626
|
+
|
|
623
627
|
const allowedPatterns = allowedUrls.map((url) => {
|
|
624
628
|
try {
|
|
625
629
|
// Prova a estrarre il dominio da una URL completa
|