@libs-ui/pipes-security-trust 0.2.356-42 → 0.2.356-43

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/README.md CHANGED
@@ -1,6 +1,25 @@
1
- # Security Trust Pipe
1
+ # @libs-ui/pipes-security-trust
2
2
 
3
- Pipe hỗ trợ đánh dấu một giá trị là an toàn (trusted) để sử dụng trong template Angular, bypassing chế Security mặc định của framework.
3
+ > Pipe đánh dấu giá trị là an toàn (trusted) để bypass chế bảo mật mặc định của Angular, tích hợp sẵn XSS Filter cho nội dung HTML động.
4
+
5
+ ## Giới thiệu
6
+
7
+ `LibsUiPipesSecurityTrustPipe` bọc `DomSanitizer` của Angular, cho phép đánh dấu một chuỗi là an toàn theo từng loại (`html`, `style`, `script`, `url`, `resourceUrl`) mà không cần gọi `DomSanitizer` thủ công trong TypeScript. Đối với loại `html`, pipe tự động áp dụng `xssFilter` từ `@libs-ui/utils` trước khi bypass để loại bỏ mã độc hại. Vì `xssFilter` là hàm bất đồng bộ, pipe trả về `Promise` — luôn kết hợp với pipe `async` trong template.
8
+
9
+ ## Tính năng
10
+
11
+ - ✅ Hỗ trợ đầy đủ 5 loại trust: `html`, `style`, `script`, `url`, `resourceUrl`
12
+ - ✅ Tích hợp `xssFilter` tự động cho loại `html` (bật mặc định, có thể tắt)
13
+ - ✅ Trả về `Promise` — an toàn với Change Detection Strategy OnPush khi dùng cùng `async` pipe
14
+ - ✅ Standalone pipe — import trực tiếp vào component, không cần module
15
+ - ✅ Dùng `inject(DomSanitizer)` theo chuẩn Angular modern
16
+
17
+ ## Khi nào sử dụng
18
+
19
+ - Hiển thị nội dung HTML động lấy từ server hoặc người dùng nhập vào (WYSIWYG editor, rich text)
20
+ - Áp dụng inline style động khi component con yêu cầu kiểu `SafeStyle` hoặc cần suppress Angular dev-mode warning
21
+ - Nhúng URL động vào thẻ `<iframe>`, `<embed>`, `<object>` (ResourceUrl)
22
+ - Sử dụng `javascript:` URL hoặc URL scheme không chuẩn trong thuộc tính `href`, `src`
4
23
 
5
24
  ## Cài đặt
6
25
 
@@ -8,47 +27,209 @@ Pipe hỗ trợ đánh dấu một giá trị là an toàn (trusted) để sử
8
27
  npm install @libs-ui/pipes-security-trust
9
28
  ```
10
29
 
11
- ## Cách sử dụng
30
+ ## Import
12
31
 
13
- Import `LibsUiPipesSecurityTrustPipe` vào component của bạn:
32
+ ```typescript
33
+ import { LibsUiPipesSecurityTrustPipe } from '@libs-ui/pipes-security-trust';
34
+ ```
35
+
36
+ Import vào component:
14
37
 
15
38
  ```typescript
39
+ import { CommonModule } from '@angular/common';
40
+ import { Component } from '@angular/core';
16
41
  import { LibsUiPipesSecurityTrustPipe } from '@libs-ui/pipes-security-trust';
42
+
43
+ @Component({
44
+ standalone: true,
45
+ imports: [CommonModule, LibsUiPipesSecurityTrustPipe],
46
+ templateUrl: './my.component.html',
47
+ })
48
+ export class MyComponent {}
49
+ ```
50
+
51
+ ## Ví dụ sử dụng
52
+
53
+ ### 1. Trusted HTML — hiển thị HTML động có XSS Filter
54
+
55
+ ```typescript
56
+ // my.component.ts
17
57
  import { CommonModule } from '@angular/common';
58
+ import { Component } from '@angular/core';
59
+ import { LibsUiPipesSecurityTrustPipe } from '@libs-ui/pipes-security-trust';
18
60
 
19
61
  @Component({
20
62
  standalone: true,
21
63
  imports: [CommonModule, LibsUiPipesSecurityTrustPipe],
22
- // ...
64
+ templateUrl: './my.component.html',
23
65
  })
24
66
  export class MyComponent {
25
- htmlContent = '<span style="color: blue">Nội dung xanh</span>';
67
+ htmlContent = '<b style="color: red">Nội dung đậm có style</b>. Được lấy từ API.';
26
68
  }
27
69
  ```
28
70
 
29
- Sử dụng trong template (luôn đi kèm với pipe `async` do trả về Promise):
30
-
31
71
  ```html
32
- <!-- Trusted HTML -->
72
+ <!-- my.component.html -->
73
+
74
+ <!-- Mặc định: Angular xóa thuộc tính style để bảo mật -->
75
+ <div [innerHTML]="htmlContent"></div>
76
+
77
+ <!-- Dùng pipe + XSS Filter (mặc định): giữ style, lọc mã độc -->
33
78
  <div [innerHTML]="htmlContent | LibsUiPipesSecurityTrustPipe:'html' | async"></div>
34
79
 
35
- <!-- Trusted Style -->
36
- <div [style.background]="gradient | LibsUiPipesSecurityTrustPipe:'style' | async"></div>
80
+ <!-- Dùng pipe nhưng tắt XSS Filter (nguy hiểm — chỉ khi nguồn hoàn toàn tin tưởng) -->
81
+ <div [innerHTML]="htmlContent | LibsUiPipesSecurityTrustPipe:'html':false | async"></div>
82
+ ```
37
83
 
38
- <!-- Trusted URL -->
39
- <a [href]="link | LibsUiPipesSecurityTrustPipe:'url' | async">Link</a>
84
+ ### 2. Resource URL — nhúng iframe
40
85
 
41
- <!-- Resource URL -->
42
- <iframe [src]="videoUrl | LibsUiPipesSecurityTrustPipe:'resourceUrl' | async"></iframe>
86
+ ```typescript
87
+ // my.component.ts
88
+ import { CommonModule } from '@angular/common';
89
+ import { Component } from '@angular/core';
90
+ import { LibsUiPipesSecurityTrustPipe } from '@libs-ui/pipes-security-trust';
91
+
92
+ @Component({
93
+ standalone: true,
94
+ imports: [CommonModule, LibsUiPipesSecurityTrustPipe],
95
+ templateUrl: './my.component.html',
96
+ })
97
+ export class MyComponent {
98
+ videoUrl = 'https://www.youtube.com/embed/dQw4w9WgXcQ';
99
+ }
43
100
  ```
44
101
 
45
- ## API
102
+ ```html
103
+ <!-- my.component.html -->
104
+
105
+ <!-- Không dùng pipe: Angular ném lỗi "unsafe value used in a resource URL context" -->
106
+ <!-- <iframe [src]="videoUrl"></iframe> ← LỖI -->
46
107
 
47
- | Tham số | Kiểu dữ liệu | Mặc định | Mô tả |
48
- | -------------- | --------------------------------------------------------- | ----------- | ------------------------------------------------- |
49
- | `type` | `'html' \| 'style' \| 'script' \| 'url' \| 'resourceUrl'` | `undefined` | Loại nội dung cần trust. |
50
- | `useXssFilter` | `boolean` | `true` | Có áp dụng `xssFilter` cho loại `html` hay không. |
108
+ <!-- Dùng pipe: iframe load bình thường -->
109
+ <iframe
110
+ [src]="videoUrl | LibsUiPipesSecurityTrustPipe:'resourceUrl' | async"
111
+ class="w-full h-full border-0"
112
+ allowfullscreen>
113
+ </iframe>
114
+ ```
51
115
 
52
- ## Lưu ý bảo mật
116
+ ### 3. Trusted URL — link với scheme không chuẩn
117
+
118
+ ```typescript
119
+ // my.component.ts
120
+ import { CommonModule } from '@angular/common';
121
+ import { Component } from '@angular/core';
122
+ import { LibsUiPipesSecurityTrustPipe } from '@libs-ui/pipes-security-trust';
123
+
124
+ @Component({
125
+ standalone: true,
126
+ imports: [CommonModule, LibsUiPipesSecurityTrustPipe],
127
+ templateUrl: './my.component.html',
128
+ })
129
+ export class MyComponent {
130
+ // Dùng trong deep link app mobile hoặc custom protocol
131
+ appDeepLink = 'myapp://open?screen=profile&userId=123';
132
+ }
133
+ ```
134
+
135
+ ```html
136
+ <!-- my.component.html -->
137
+
138
+ <!-- Không dùng pipe: Angular thêm prefix "unsafe:" vào href -->
139
+ <a [href]="appDeepLink">Mở ứng dụng (Bị chặn)</a>
140
+
141
+ <!-- Dùng pipe: href được gán nguyên vẹn -->
142
+ <a [href]="appDeepLink | LibsUiPipesSecurityTrustPipe:'url' | async">Mở ứng dụng</a>
143
+ ```
144
+
145
+ ### 4. Trusted Style — component yêu cầu kiểu SafeStyle
146
+
147
+ ```typescript
148
+ // my.component.ts
149
+ import { CommonModule } from '@angular/common';
150
+ import { Component } from '@angular/core';
151
+ import { LibsUiPipesSecurityTrustPipe } from '@libs-ui/pipes-security-trust';
152
+
153
+ @Component({
154
+ standalone: true,
155
+ imports: [CommonModule, LibsUiPipesSecurityTrustPipe],
156
+ templateUrl: './my.component.html',
157
+ })
158
+ export class MyComponent {
159
+ gradientStyle = 'background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 16px; border-radius: 8px;';
160
+ }
161
+ ```
162
+
163
+ ```html
164
+ <!-- my.component.html -->
165
+
166
+ <!-- Dùng khi component con yêu cầu kiểu SafeStyle hoặc suppress Angular dev-mode warning -->
167
+ <div [attr.style]="gradientStyle | LibsUiPipesSecurityTrustPipe:'style' | async">
168
+ Nội dung với gradient động
169
+ </div>
170
+ ```
171
+
172
+ ## Transform
173
+
174
+ Cú pháp pipe:
175
+
176
+ ```
177
+ value | LibsUiPipesSecurityTrustPipe : type : useXssFilter | async
178
+ ```
179
+
180
+ | Tham số | Type | Bắt buộc | Mô tả | Ví dụ |
181
+ |---|---|---|---|---|
182
+ | `value` | `string` | Có | Chuỗi cần đánh dấu an toàn | `'<b>text</b>'` |
183
+ | `type` | `'html' \| 'style' \| 'script' \| 'url' \| 'resourceUrl'` | Có | Loại nội dung cần trust | `'html'` |
184
+ | `useXssFilter` | `boolean` | Không | Bật/tắt XSS Filter — chỉ áp dụng với `type: 'html'`. Mặc định `true` | `false` |
185
+
186
+ **Giá trị trả về (Return type):**
187
+
188
+ | `type` | Return type |
189
+ |---|---|
190
+ | `'html'` | `Promise<SafeHtml>` |
191
+ | `'style'` | `Promise<SafeStyle>` |
192
+ | `'script'` | `Promise<SafeScript>` |
193
+ | `'url'` | `Promise<SafeUrl>` |
194
+ | `'resourceUrl'` | `Promise<SafeResourceUrl>` |
195
+
196
+ **Ví dụ standalone (gọi trực tiếp trong TypeScript):**
197
+
198
+ ```typescript
199
+ import { inject } from '@angular/core';
200
+ import { LibsUiPipesSecurityTrustPipe } from '@libs-ui/pipes-security-trust';
201
+
202
+ // Trong constructor hoặc method
203
+ const pipe = inject(LibsUiPipesSecurityTrustPipe);
204
+
205
+ // HTML với XSS Filter
206
+ const safeHtml = await pipe.transform('<b style="color:red">text</b>', 'html');
207
+
208
+ // HTML không dùng XSS Filter
209
+ const rawHtml = await pipe.transform('<b>text</b>', 'html', false);
210
+
211
+ // Resource URL
212
+ const safeUrl = await pipe.transform('https://www.youtube.com/embed/abc123', 'resourceUrl');
213
+ ```
214
+
215
+ ## Lưu ý quan trọng
216
+
217
+ ⚠️ **Luôn dùng pipe `async` trong template**: Vì `transform()` trả về `Promise`, bắt buộc phải pipe qua `async` (từ `CommonModule`) để Angular unwrap giá trị. Thiếu `async` sẽ khiến template nhận được object `Promise` thay vì giá trị thực.
218
+
219
+ ⚠️ **Bypass cơ chế bảo mật của Angular**: Pipe này vô hiệu hóa DomSanitizer cho giá trị được truyền vào. Chỉ sử dụng với nội dung từ nguồn mà bạn hoàn toàn kiểm soát hoặc đã xử lý phía server.
220
+
221
+ ⚠️ **XSS Filter chỉ áp dụng cho type `'html'`**: Các loại `style`, `script`, `url`, `resourceUrl` không qua XSS Filter — developer chịu trách nhiệm đảm bảo an toàn cho nội dung đầu vào.
222
+
223
+ ⚠️ **`type: 'style'` ít cần thiết với Angular 14+**: Angular 14+ đã relaxed bộ style sanitizer, CSS property thông thường (`color`, `background`, `font-size`...) không bị chặn ngay cả khi không dùng pipe. Chỉ cần loại `style` khi component con yêu cầu kiểu TypeScript `SafeStyle` hoặc cần suppress dev-mode warning.
224
+
225
+ ⚠️ **`type: 'script'` rất hiếm dùng**: Angular không có binding nào yêu cầu `SafeScript` trong template thông thường. Chỉ sử dụng khi tích hợp với thư viện bên thứ ba có yêu cầu đặc biệt.
226
+
227
+ ⚠️ **Truyền `false` cho `useXssFilter` là nguy hiểm**: Chỉ tắt XSS Filter khi nội dung HTML đã được sanitize hoàn toàn ở phía server và bạn cần giữ nguyên toàn bộ markup.
228
+
229
+ ## Demo
230
+
231
+ ```bash
232
+ npx nx serve core-ui
233
+ ```
53
234
 
54
- Pipe này bypass cơ chế bảo mật của Angular. Chỉ sử dụng với các nội dung mà bạn hoàn toàn tin tưởng. Mặc định `xssFilter` được bật cho loại `html` để tăng thêm một lớp bảo mật.
235
+ Truy cập: http://localhost:4500/pipes/security-trust
@@ -1 +1 @@
1
- {"version":3,"file":"libs-ui-pipes-security-trust.mjs","sources":["../../../../../libs-ui/pipes/security-trust/src/security-trust.pipe.ts","../../../../../libs-ui/pipes/security-trust/src/libs-ui-pipes-security-trust.ts"],"sourcesContent":["import { Pipe, PipeTransform, inject } from '@angular/core';\nimport { DomSanitizer, SafeHtml, SafeResourceUrl, SafeScript, SafeStyle, SafeUrl } from '@angular/platform-browser';\nimport { xssFilter } from '@libs-ui/utils';\n\n@Pipe({\n name: 'LibsUiPipesSecurityTrustPipe',\n standalone: true,\n})\nexport class LibsUiPipesSecurityTrustPipe implements PipeTransform {\n private readonly sanitizer = inject(DomSanitizer);\n\n public async transform(value: string, type: string, useXssFilter = true): Promise<SafeHtml | SafeStyle | SafeScript | SafeUrl | SafeResourceUrl> {\n switch (type) {\n case 'html':\n return this.sanitizer.bypassSecurityTrustHtml(useXssFilter ? await xssFilter(value) : value);\n\n case 'style':\n return this.sanitizer.bypassSecurityTrustStyle(value);\n\n case 'script':\n return this.sanitizer.bypassSecurityTrustScript(value);\n\n case 'url':\n return this.sanitizer.bypassSecurityTrustUrl(value);\n\n case 'resourceUrl':\n return this.sanitizer.bypassSecurityTrustResourceUrl(value);\n\n default:\n throw new Error(`Invalid safe type specified: ${type}`);\n }\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;;;MAQa,4BAA4B,CAAA;AACtB,IAAA,SAAS,GAAG,MAAM,CAAC,YAAY,CAAC;IAE1C,MAAM,SAAS,CAAC,KAAa,EAAE,IAAY,EAAE,YAAY,GAAG,IAAI,EAAA;QACrE,QAAQ,IAAI;AACV,YAAA,KAAK,MAAM;gBACT,OAAO,IAAI,CAAC,SAAS,CAAC,uBAAuB,CAAC,YAAY,GAAG,MAAM,SAAS,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC;AAE9F,YAAA,KAAK,OAAO;gBACV,OAAO,IAAI,CAAC,SAAS,CAAC,wBAAwB,CAAC,KAAK,CAAC;AAEvD,YAAA,KAAK,QAAQ;gBACX,OAAO,IAAI,CAAC,SAAS,CAAC,yBAAyB,CAAC,KAAK,CAAC;AAExD,YAAA,KAAK,KAAK;gBACR,OAAO,IAAI,CAAC,SAAS,CAAC,sBAAsB,CAAC,KAAK,CAAC;AAErD,YAAA,KAAK,aAAa;gBAChB,OAAO,IAAI,CAAC,SAAS,CAAC,8BAA8B,CAAC,KAAK,CAAC;AAE7D,YAAA;AACE,gBAAA,MAAM,IAAI,KAAK,CAAC,gCAAgC,IAAI,CAAA,CAAE,CAAC;;IAE7D;wGAvBW,4BAA4B,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,IAAA,EAAA,CAAA;sGAA5B,4BAA4B,EAAA,YAAA,EAAA,IAAA,EAAA,IAAA,EAAA,8BAAA,EAAA,CAAA;;4FAA5B,4BAA4B,EAAA,UAAA,EAAA,CAAA;kBAJxC,IAAI;AAAC,YAAA,IAAA,EAAA,CAAA;AACJ,oBAAA,IAAI,EAAE,8BAA8B;AACpC,oBAAA,UAAU,EAAE,IAAI;AACjB,iBAAA;;;ACPD;;AAEG;;;;"}
1
+ {"version":3,"file":"libs-ui-pipes-security-trust.mjs","sources":["../../../../../libs-ui/pipes/security-trust/src/security-trust.pipe.ts","../../../../../libs-ui/pipes/security-trust/src/libs-ui-pipes-security-trust.ts"],"sourcesContent":["import { Pipe, PipeTransform, inject } from '@angular/core';\nimport { DomSanitizer, SafeHtml, SafeResourceUrl, SafeScript, SafeStyle, SafeUrl } from '@angular/platform-browser';\nimport { xssFilter } from '@libs-ui/utils';\n\n@Pipe({\n name: 'LibsUiPipesSecurityTrustPipe',\n standalone: true,\n})\nexport class LibsUiPipesSecurityTrustPipe implements PipeTransform {\n private readonly sanitizer = inject(DomSanitizer);\n\n public async transform(value: string, type: string, useXssFilter = true): Promise<SafeHtml | SafeStyle | SafeScript | SafeUrl | SafeResourceUrl> {\n switch (type) {\n case 'html':\n return this.sanitizer.bypassSecurityTrustHtml(useXssFilter ? await xssFilter(value) : value);\n\n case 'style':\n return this.sanitizer.bypassSecurityTrustStyle(value);\n\n case 'script':\n return this.sanitizer.bypassSecurityTrustScript(value);\n\n case 'url':\n return this.sanitizer.bypassSecurityTrustUrl(value);\n\n case 'resourceUrl':\n return this.sanitizer.bypassSecurityTrustResourceUrl(value);\n\n default:\n throw new Error(`Invalid safe type specified: ${type}`);\n }\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;;;MAQa,4BAA4B,CAAA;AACtB,IAAA,SAAS,GAAG,MAAM,CAAC,YAAY,CAAC,CAAC;IAE3C,MAAM,SAAS,CAAC,KAAa,EAAE,IAAY,EAAE,YAAY,GAAG,IAAI,EAAA;QACrE,QAAQ,IAAI;AACV,YAAA,KAAK,MAAM;gBACT,OAAO,IAAI,CAAC,SAAS,CAAC,uBAAuB,CAAC,YAAY,GAAG,MAAM,SAAS,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC,CAAC;AAE/F,YAAA,KAAK,OAAO;gBACV,OAAO,IAAI,CAAC,SAAS,CAAC,wBAAwB,CAAC,KAAK,CAAC,CAAC;AAExD,YAAA,KAAK,QAAQ;gBACX,OAAO,IAAI,CAAC,SAAS,CAAC,yBAAyB,CAAC,KAAK,CAAC,CAAC;AAEzD,YAAA,KAAK,KAAK;gBACR,OAAO,IAAI,CAAC,SAAS,CAAC,sBAAsB,CAAC,KAAK,CAAC,CAAC;AAEtD,YAAA,KAAK,aAAa;gBAChB,OAAO,IAAI,CAAC,SAAS,CAAC,8BAA8B,CAAC,KAAK,CAAC,CAAC;AAE9D,YAAA;AACE,gBAAA,MAAM,IAAI,KAAK,CAAC,gCAAgC,IAAI,CAAA,CAAE,CAAC,CAAC;SAC3D;KACF;wGAvBU,4BAA4B,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,IAAA,EAAA,CAAA,CAAA;sGAA5B,4BAA4B,EAAA,YAAA,EAAA,IAAA,EAAA,IAAA,EAAA,8BAAA,EAAA,CAAA,CAAA;;4FAA5B,4BAA4B,EAAA,UAAA,EAAA,CAAA;kBAJxC,IAAI;AAAC,YAAA,IAAA,EAAA,CAAA;AACJ,oBAAA,IAAI,EAAE,8BAA8B;AACpC,oBAAA,UAAU,EAAE,IAAI;AACjB,iBAAA,CAAA;;;ACPD;;AAEG;;;;"}
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@libs-ui/pipes-security-trust",
3
- "version": "0.2.356-42",
3
+ "version": "0.2.356-43",
4
4
  "peerDependencies": {
5
5
  "@angular/core": ">=18.0.0",
6
6
  "@angular/platform-browser": ">=18.0.0",
7
- "@libs-ui/utils": "0.2.356-42"
7
+ "@libs-ui/utils": "0.2.356-43"
8
8
  },
9
9
  "sideEffects": false,
10
10
  "module": "fesm2022/libs-ui-pipes-security-trust.mjs",