acrylblends 0.6.3 → 0.6.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.
Files changed (269) hide show
  1. package/README.md +3 -2
  2. package/docs/framework/README.md +2 -2
  3. package/docs/framework/UPSTREAM.md +1 -1
  4. package/docs/framework/guides/jsx.md +24 -0
  5. package/docs/framework/helpers/ssg.md +3 -6
  6. package/docs/framework/middleware/builtin/jsx-renderer.md +0 -3
  7. package/docs/framework/upstream.json +2 -2
  8. package/lib/accepts.d.ts +1 -1
  9. package/lib/acryl-base.d.ts +1 -1
  10. package/lib/adapter.d.ts +1 -1
  11. package/lib/{app-wFwpg-bt.d.ts → app-D8riatvv.d.ts} +1 -1
  12. package/lib/basic-auth.d.ts +1 -1
  13. package/lib/bearer-auth.d.ts +1 -1
  14. package/lib/body-limit.d.ts +1 -1
  15. package/lib/cache.d.ts +1 -1
  16. package/lib/cache.js +4 -4
  17. package/lib/{client-BHTr318g.js → client-DDLXwhBo.js} +2 -125
  18. package/lib/client.d.ts +2 -2
  19. package/lib/client.js +2 -1
  20. package/lib/combine.d.ts +1 -1
  21. package/lib/{components-Ce5FRyHU.js → components-0o0CBYNv.js} +2 -2
  22. package/lib/{components-DYZdxJIJ.js → components-DdI7-ns7.js} +1 -1
  23. package/lib/compress.d.ts +1 -1
  24. package/lib/conninfo.d.ts +2 -2
  25. package/lib/{context-DVQBjuns.d.ts → context-DS3fYyG-.d.ts} +1 -1
  26. package/lib/context-storage.d.ts +1 -1
  27. package/lib/cookie.d.ts +1 -1
  28. package/lib/cors.d.ts +1 -1
  29. package/lib/csrf.d.ts +1 -1
  30. package/lib/dev.d.ts +2 -2
  31. package/lib/etag.d.ts +1 -1
  32. package/lib/factory.d.ts +2 -2
  33. package/lib/{hooks-Bq5q9IMl.js → hooks-BMw6BAyP.js} +5 -5
  34. package/lib/{index-CUTfU69R.d.ts → index-Bb7YJKCq.d.ts} +2 -2
  35. package/lib/{index-CsvB-F9j.d.ts → index-BvFh1Gfx.d.ts} +1 -1
  36. package/lib/{index-Cqcdluyn.d.ts → index-CTy4N7ng.d.ts} +2 -2
  37. package/lib/index.d.ts +4 -4
  38. package/lib/ip-restriction.d.ts +2 -2
  39. package/lib/jsx/dom/client.js +1 -1
  40. package/lib/jsx/dom/jsx-dev-runtime.js +1 -1
  41. package/lib/jsx/dom/jsx-runtime.js +1 -1
  42. package/lib/jsx/dom/server.js +1 -1
  43. package/lib/jsx/dom.js +3 -3
  44. package/lib/jsx/streaming.js +1 -1
  45. package/lib/{jsx-dev-runtime-kAhR_4C7.js → jsx-dev-runtime-D18Y35TI.js} +1 -1
  46. package/lib/jsx-renderer.d.ts +75 -0
  47. package/lib/jsx-renderer.js +99 -0
  48. package/lib/jsx.js +3 -3
  49. package/lib/jwk.d.ts +1 -1
  50. package/lib/jwt.d.ts +1 -1
  51. package/lib/language.d.ts +1 -1
  52. package/lib/logger.d.ts +1 -1
  53. package/lib/loopback-only.d.ts +1 -1
  54. package/lib/method-not-allowed.d.ts +2 -2
  55. package/lib/method-override.d.ts +2 -2
  56. package/lib/mount.d.ts +1 -1
  57. package/lib/node-server/conninfo.d.ts +1 -1
  58. package/lib/node-server/serve-static.d.ts +1 -1
  59. package/lib/node-server/serve-static.js +1 -1
  60. package/lib/node-server.d.ts +1 -1
  61. package/lib/node-server.js +1 -1
  62. package/lib/powered-by.d.ts +1 -1
  63. package/lib/pretty-json.d.ts +1 -1
  64. package/lib/quick.d.ts +1 -1
  65. package/lib/request-id.d.ts +1 -1
  66. package/lib/request.d.ts +1 -1
  67. package/lib/route.d.ts +1 -1
  68. package/lib/schema-validator.d.ts +1 -1
  69. package/lib/secure-headers.d.ts +1 -1
  70. package/lib/{serve-static-Cw23shXv.js → serve-static-B14MF1Va.js} +1 -0
  71. package/lib/serve-static.d.ts +1 -1
  72. package/lib/ssg-BwjcA-Ge.js +389 -0
  73. package/lib/ssg.d.ts +156 -0
  74. package/lib/ssg.js +2 -0
  75. package/lib/streaming.d.ts +1 -1
  76. package/lib/testing.d.ts +3 -3
  77. package/lib/testing.js +1 -1
  78. package/lib/timeout.d.ts +1 -1
  79. package/lib/timing.d.ts +1 -1
  80. package/lib/tiny.d.ts +1 -1
  81. package/lib/trailing-slash.d.ts +1 -1
  82. package/lib/{types-nEL8VPDC.d.ts → types-Dv_nV2cv.d.ts} +1 -1
  83. package/lib/{types-CQiGmsWW.d.ts → types-zNxyEpG2.d.ts} +2 -2
  84. package/lib/types.d.ts +1 -1
  85. package/lib/utils/body.d.ts +1 -1
  86. package/lib/utils/ipaddr.d.ts +1 -1
  87. package/lib/utils-Cx61GFMC.js +125 -0
  88. package/lib/validator.d.ts +1 -1
  89. package/lib/ws.d.ts +1 -1
  90. package/package.json +9 -1
  91. package/plugins/acryl-inspect/upstream.json +1 -1
  92. package/plugins/acryl-node-server/upstream.json +1 -1
  93. package/plugins/acryl-router/src/core/helper/ssg/index.ts +14 -0
  94. package/plugins/acryl-router/src/core/helper/ssg/middleware.ts +83 -0
  95. package/plugins/acryl-router/src/core/helper/ssg/plugins.ts +72 -0
  96. package/plugins/acryl-router/src/core/helper/ssg/ssg.ts +471 -0
  97. package/plugins/acryl-router/src/core/helper/ssg/utils.ts +118 -0
  98. package/plugins/acryl-router/src/core/jsx/dom/render.ts +6 -6
  99. package/plugins/acryl-router/src/core/middleware/cache/index.ts +4 -4
  100. package/plugins/acryl-router/src/core/middleware/jsx-renderer/index.ts +162 -0
  101. package/plugins/acryl-router/src/helpers/index.ts +1 -0
  102. package/plugins/acryl-router/src/middleware/index.ts +1 -0
  103. package/plugins/acryl-router/upstream.json +2 -2
  104. package/plugins/acryl-router-http/upstream.json +1 -1
  105. package/plugins/acryl-state/upstream.json +1 -1
  106. package/plugins/desktop/upstream.json +1 -1
  107. package/plugins/desktop-web/upstream.json +1 -1
  108. package/plugins/extensions/resolve.ts +4 -0
  109. package/shared/AGENTS.core.md +4 -0
  110. package/templates/agent/tsconfig.json +7 -1
  111. package/templates/todo/upstream.json +1 -1
  112. package/plugins/acryl-inspect/tests/report.spec.ts +0 -69
  113. package/plugins/acryl-inspect/tests/service.spec.ts +0 -121
  114. package/plugins/acryl-node-server/tests/adapter/app.ts +0 -76
  115. package/plugins/acryl-node-server/tests/adapter/assets/.static/plain.txt +0 -1
  116. package/plugins/acryl-node-server/tests/adapter/assets/favicon.ico +0 -0
  117. package/plugins/acryl-node-server/tests/adapter/assets/secret.txt +0 -1
  118. package/plugins/acryl-node-server/tests/adapter/assets/static/acryl.html +0 -1
  119. package/plugins/acryl-node-server/tests/adapter/assets/static/admin/secret.txt +0 -1
  120. package/plugins/acryl-node-server/tests/adapter/assets/static/data.json +0 -5
  121. package/plugins/acryl-node-server/tests/adapter/assets/static/extensionless +0 -1
  122. package/plugins/acryl-node-server/tests/adapter/assets/static/foo..bar.txt +0 -0
  123. package/plugins/acryl-node-server/tests/adapter/assets/static/index.html +0 -1
  124. package/plugins/acryl-node-server/tests/adapter/assets/static/plain.txt +0 -1
  125. package/plugins/acryl-node-server/tests/adapter/assets/static-with-context-path/plain.txt +0 -1
  126. package/plugins/acryl-node-server/tests/adapter/assets/static-with-precompressed/hello.bin +0 -1
  127. package/plugins/acryl-node-server/tests/adapter/assets/static-with-precompressed/hello.bin.br +0 -1
  128. package/plugins/acryl-node-server/tests/adapter/assets/static-with-precompressed/hello.txt +0 -1
  129. package/plugins/acryl-node-server/tests/adapter/assets/static-with-precompressed/hello.txt.br +0 -1
  130. package/plugins/acryl-node-server/tests/adapter/assets/static-with-precompressed/hello.txt.zst +0 -1
  131. package/plugins/acryl-node-server/tests/adapter/conninfo.test.ts +0 -34
  132. package/plugins/acryl-node-server/tests/adapter/content-length.test.ts +0 -248
  133. package/plugins/acryl-node-server/tests/adapter/early-hints.test.ts +0 -457
  134. package/plugins/acryl-node-server/tests/adapter/fixtures/keys/agent1-cert.pem +0 -23
  135. package/plugins/acryl-node-server/tests/adapter/fixtures/keys/agent1-key.pem +0 -27
  136. package/plugins/acryl-node-server/tests/adapter/headers.test.ts +0 -252
  137. package/plugins/acryl-node-server/tests/adapter/helpers/request.ts +0 -190
  138. package/plugins/acryl-node-server/tests/adapter/listener.test.ts +0 -727
  139. package/plugins/acryl-node-server/tests/adapter/request-client-disconnect.test.ts +0 -189
  140. package/plugins/acryl-node-server/tests/adapter/request.test.ts +0 -1230
  141. package/plugins/acryl-node-server/tests/adapter/response.test.ts +0 -285
  142. package/plugins/acryl-node-server/tests/adapter/serve-static.test.ts +0 -849
  143. package/plugins/acryl-node-server/tests/adapter/server-socket.test.ts +0 -790
  144. package/plugins/acryl-node-server/tests/adapter/server.test.ts +0 -1312
  145. package/plugins/acryl-node-server/tests/adapter/setup.ts +0 -16
  146. package/plugins/acryl-node-server/tests/adapter/url.test.ts +0 -76
  147. package/plugins/acryl-node-server/tests/adapter/utils/response.test.ts +0 -23
  148. package/plugins/acryl-node-server/tests/adapter/utils/stream.test.ts +0 -75
  149. package/plugins/acryl-node-server/tests/adapter/utils.test.ts +0 -235
  150. package/plugins/acryl-node-server/tests/adapter/websocket.test.ts +0 -260
  151. package/plugins/acryl-node-server/tests/server.spec.ts +0 -141
  152. package/plugins/acryl-router/src/core/app.test.ts +0 -3833
  153. package/plugins/acryl-router/src/core/client/client.test.ts +0 -2313
  154. package/plugins/acryl-router/src/core/client/types.test.ts +0 -149
  155. package/plugins/acryl-router/src/core/client/utils.test.ts +0 -405
  156. package/plugins/acryl-router/src/core/compose.test.ts +0 -751
  157. package/plugins/acryl-router/src/core/context.test.ts +0 -629
  158. package/plugins/acryl-router/src/core/helper/accepts/accepts.test.ts +0 -344
  159. package/plugins/acryl-router/src/core/helper/adapter/index.test.ts +0 -55
  160. package/plugins/acryl-router/src/core/helper/cookie/index.test.ts +0 -510
  161. package/plugins/acryl-router/src/core/helper/css/common.case.test.tsx +0 -506
  162. package/plugins/acryl-router/src/core/helper/css/index.test.tsx +0 -678
  163. package/plugins/acryl-router/src/core/helper/dev/index.test.ts +0 -181
  164. package/plugins/acryl-router/src/core/helper/factory/index.test.ts +0 -434
  165. package/plugins/acryl-router/src/core/helper/html/index.test.ts +0 -78
  166. package/plugins/acryl-router/src/core/helper/proxy/index.test.ts +0 -356
  167. package/plugins/acryl-router/src/core/helper/route/index.test.ts +0 -259
  168. package/plugins/acryl-router/src/core/helper/streaming/sse.test.tsx +0 -557
  169. package/plugins/acryl-router/src/core/helper/streaming/stream.test.ts +0 -128
  170. package/plugins/acryl-router/src/core/helper/streaming/text.test.ts +0 -34
  171. package/plugins/acryl-router/src/core/helper/testing/index.test.ts +0 -42
  172. package/plugins/acryl-router/src/core/helper/websocket/index.test.ts +0 -124
  173. package/plugins/acryl-router/src/core/http-exception.test.ts +0 -45
  174. package/plugins/acryl-router/src/core/jsx/base.test.tsx +0 -97
  175. package/plugins/acryl-router/src/core/jsx/children.test.ts +0 -52
  176. package/plugins/acryl-router/src/core/jsx/components.test.tsx +0 -936
  177. package/plugins/acryl-router/src/core/jsx/context-isolation.test.ts +0 -655
  178. package/plugins/acryl-router/src/core/jsx/dom/client.test.tsx +0 -128
  179. package/plugins/acryl-router/src/core/jsx/dom/components.test.tsx +0 -330
  180. package/plugins/acryl-router/src/core/jsx/dom/context.test.tsx +0 -184
  181. package/plugins/acryl-router/src/core/jsx/dom/css.test.tsx +0 -149
  182. package/plugins/acryl-router/src/core/jsx/dom/hooks/index.test.tsx +0 -172
  183. package/plugins/acryl-router/src/core/jsx/dom/index.test.tsx +0 -3681
  184. package/plugins/acryl-router/src/core/jsx/dom/intrinsic-element/components.test.tsx +0 -1344
  185. package/plugins/acryl-router/src/core/jsx/dom/server.test.tsx +0 -199
  186. package/plugins/acryl-router/src/core/jsx/hooks/dom.test.tsx +0 -859
  187. package/plugins/acryl-router/src/core/jsx/hooks/string.test.tsx +0 -40
  188. package/plugins/acryl-router/src/core/jsx/index.test.tsx +0 -1744
  189. package/plugins/acryl-router/src/core/jsx/intrinsic-element/components.test.tsx +0 -666
  190. package/plugins/acryl-router/src/core/jsx/jsx-runtime.test.tsx +0 -85
  191. package/plugins/acryl-router/src/core/jsx/streaming.test.tsx +0 -1281
  192. package/plugins/acryl-router/src/core/jsx/utils.test.ts +0 -366
  193. package/plugins/acryl-router/src/core/middleware/basic-auth/index.test.ts +0 -434
  194. package/plugins/acryl-router/src/core/middleware/bearer-auth/index.test.ts +0 -1018
  195. package/plugins/acryl-router/src/core/middleware/body-limit/index.test.ts +0 -273
  196. package/plugins/acryl-router/src/core/middleware/cache/index.test.ts +0 -1211
  197. package/plugins/acryl-router/src/core/middleware/combine/index.test.ts +0 -355
  198. package/plugins/acryl-router/src/core/middleware/compress/index.test.ts +0 -535
  199. package/plugins/acryl-router/src/core/middleware/context-storage/index.test.ts +0 -43
  200. package/plugins/acryl-router/src/core/middleware/cors/index.test.ts +0 -532
  201. package/plugins/acryl-router/src/core/middleware/csrf/index.test.ts +0 -534
  202. package/plugins/acryl-router/src/core/middleware/etag/digest.test.ts +0 -21
  203. package/plugins/acryl-router/src/core/middleware/etag/index.test.ts +0 -503
  204. package/plugins/acryl-router/src/core/middleware/ip-restriction/index.test.ts +0 -217
  205. package/plugins/acryl-router/src/core/middleware/jwk/index.test.ts +0 -1135
  206. package/plugins/acryl-router/src/core/middleware/jwk/keys.test.json +0 -48
  207. package/plugins/acryl-router/src/core/middleware/jwt/index.test.ts +0 -802
  208. package/plugins/acryl-router/src/core/middleware/language/index.test.ts +0 -552
  209. package/plugins/acryl-router/src/core/middleware/logger/index.test.ts +0 -204
  210. package/plugins/acryl-router/src/core/middleware/method-not-allowed/index.test.ts +0 -292
  211. package/plugins/acryl-router/src/core/middleware/method-override/index.test.ts +0 -221
  212. package/plugins/acryl-router/src/core/middleware/mount/index.test.ts +0 -334
  213. package/plugins/acryl-router/src/core/middleware/powered-by/index.test.ts +0 -37
  214. package/plugins/acryl-router/src/core/middleware/pretty-json/index.test.ts +0 -218
  215. package/plugins/acryl-router/src/core/middleware/request-id/index.test.ts +0 -168
  216. package/plugins/acryl-router/src/core/middleware/secure-headers/index.test.ts +0 -671
  217. package/plugins/acryl-router/src/core/middleware/serve-static/index.test.ts +0 -450
  218. package/plugins/acryl-router/src/core/middleware/serve-static/path.test.ts +0 -50
  219. package/plugins/acryl-router/src/core/middleware/timeout/index.test.ts +0 -70
  220. package/plugins/acryl-router/src/core/middleware/timing/index.test.ts +0 -310
  221. package/plugins/acryl-router/src/core/middleware/trailing-slash/index.test.ts +0 -381
  222. package/plugins/acryl-router/src/core/preset/quick.test.ts +0 -42
  223. package/plugins/acryl-router/src/core/preset/tiny.test.ts +0 -42
  224. package/plugins/acryl-router/src/core/request.test.ts +0 -751
  225. package/plugins/acryl-router/src/core/router/common.case.test.ts +0 -1132
  226. package/plugins/acryl-router/src/core/router/linear-router/router.test.ts +0 -80
  227. package/plugins/acryl-router/src/core/router/pattern-router/router.test.ts +0 -46
  228. package/plugins/acryl-router/src/core/router/reg-exp-router/prepared-router.test.ts +0 -154
  229. package/plugins/acryl-router/src/core/router/reg-exp-router/router.test.ts +0 -265
  230. package/plugins/acryl-router/src/core/router/smart-router/router.test.ts +0 -13
  231. package/plugins/acryl-router/src/core/router/trie-router/node.test.ts +0 -896
  232. package/plugins/acryl-router/src/core/router/trie-router/router.test.ts +0 -8
  233. package/plugins/acryl-router/src/core/types.test.ts +0 -4134
  234. package/plugins/acryl-router/src/core/utils/accept.test.ts +0 -299
  235. package/plugins/acryl-router/src/core/utils/basic-auth.test.ts +0 -56
  236. package/plugins/acryl-router/src/core/utils/body.test.ts +0 -496
  237. package/plugins/acryl-router/src/core/utils/buffer.test.ts +0 -147
  238. package/plugins/acryl-router/src/core/utils/color.test.ts +0 -23
  239. package/plugins/acryl-router/src/core/utils/concurrent.test.ts +0 -69
  240. package/plugins/acryl-router/src/core/utils/cookie.test.ts +0 -460
  241. package/plugins/acryl-router/src/core/utils/crypto.test.ts +0 -43
  242. package/plugins/acryl-router/src/core/utils/encode.test.ts +0 -61
  243. package/plugins/acryl-router/src/core/utils/filepath.test.ts +0 -78
  244. package/plugins/acryl-router/src/core/utils/html.test.ts +0 -16
  245. package/plugins/acryl-router/src/core/utils/ipaddr.test.ts +0 -149
  246. package/plugins/acryl-router/src/core/utils/jwt/jwa.test.ts +0 -86
  247. package/plugins/acryl-router/src/core/utils/jwt/jwt.test.ts +0 -1788
  248. package/plugins/acryl-router/src/core/utils/mime.test.ts +0 -64
  249. package/plugins/acryl-router/src/core/utils/stream.test.ts +0 -212
  250. package/plugins/acryl-router/src/core/utils/types.test.ts +0 -295
  251. package/plugins/acryl-router/src/core/utils/url.test.ts +0 -384
  252. package/plugins/acryl-router/src/core/validator/utils.test.ts +0 -82
  253. package/plugins/acryl-router/src/core/validator/validator.test.ts +0 -1488
  254. package/plugins/acryl-router/tests/docs-examples.spec.ts +0 -152
  255. package/plugins/acryl-router/tests/jsx.spec.tsx +0 -63
  256. package/plugins/acryl-router/tests/live-install.spec.ts +0 -64
  257. package/plugins/acryl-router/tests/loader.spec.ts +0 -72
  258. package/plugins/acryl-router/tests/loopback-only.spec.ts +0 -80
  259. package/plugins/acryl-router/tests/no-dom/consumer.ts +0 -11
  260. package/plugins/acryl-router/tests/no-dom/tsconfig.json +0 -13
  261. package/plugins/acryl-router/tests/service.spec.ts +0 -426
  262. package/plugins/acryl-router/tests/shadow-state.spec.ts +0 -79
  263. package/plugins/acryl-router-http/tests/adapter.spec.ts +0 -174
  264. package/plugins/acryl-router-http/tests/stream.spec.ts +0 -133
  265. package/plugins/acryl-router-http/tests/surfaces.spec.ts +0 -101
  266. package/plugins/acryl-state/src/react.ts +0 -11
  267. package/plugins/acryl-state/tests/cell.spec.ts +0 -71
  268. package/plugins/acryl-state/tests/react.spec.ts +0 -39
  269. package/plugins/acryl-state/tests/service.spec.ts +0 -132
@@ -1,671 +0,0 @@
1
- import { NONCE, secureHeaders } from './index.ts'
2
- import type { ContentSecurityPolicyOptionHandler } from './index.ts'
3
- import { Acryl } from '../../app.ts'
4
- import { poweredBy } from '../powered-by/index.ts'
5
-
6
- declare module '../../context.ts' {
7
- interface ContextVariableMap {
8
- ['test-scriptSrc-nonce']?: string
9
- ['test-styleSrc-nonce']?: string
10
- }
11
- }
12
-
13
- describe('Secure Headers Middleware', () => {
14
- it('default middleware', async () => {
15
- const app = new Acryl()
16
- app.use('*', secureHeaders())
17
- app.get('/test', async (ctx) => {
18
- return ctx.text('test')
19
- })
20
-
21
- const res = await app.request('/test')
22
- expect(res).not.toBeNull()
23
- expect(res.status).toBe(200)
24
- expect(res.headers.get('X-Frame-Options')).toEqual('SAMEORIGIN')
25
- expect(res.headers.get('Strict-Transport-Security')).toEqual(
26
- 'max-age=15552000; includeSubDomains'
27
- )
28
- expect(res.headers.get('X-Download-Options')).toEqual('noopen')
29
- expect(res.headers.get('X-XSS-Protection')).toEqual('0')
30
- expect(res.headers.get('X-Powered-By')).toBeNull()
31
- expect(res.headers.get('X-DNS-Prefetch-Control')).toEqual('off')
32
- expect(res.headers.get('X-Content-Type-Options')).toEqual('nosniff')
33
- expect(res.headers.get('Referrer-Policy')).toEqual('no-referrer')
34
- expect(res.headers.get('X-Permitted-Cross-Domain-Policies')).toEqual('none')
35
- expect(res.headers.get('Cross-Origin-Resource-Policy')).toEqual('same-origin')
36
- expect(res.headers.get('Cross-Origin-Opener-Policy')).toEqual('same-origin')
37
- expect(res.headers.get('Origin-Agent-Cluster')).toEqual('?1')
38
- expect(res.headers.get('Permissions-Policy')).toBeNull()
39
- expect(res.headers.get('Content-Security-Policy')).toBeFalsy()
40
- expect(res.headers.get('Content-Security-Policy-ReportOnly')).toBeFalsy()
41
- })
42
-
43
- it('all headers enabled', async () => {
44
- const app = new Acryl()
45
- app.use(
46
- '*',
47
- secureHeaders({
48
- contentSecurityPolicy: {
49
- defaultSrc: ["'self'"],
50
- },
51
- contentSecurityPolicyReportOnly: {
52
- defaultSrc: ["'self'"],
53
- },
54
- crossOriginEmbedderPolicy: true,
55
- permissionsPolicy: {
56
- camera: [],
57
- },
58
- })
59
- )
60
- app.get('/test', async (ctx) => {
61
- return ctx.text('test')
62
- })
63
-
64
- const res = await app.request('/test')
65
- expect(res).not.toBeNull()
66
- expect(res.status).toBe(200)
67
- expect(res.headers.get('X-Frame-Options')).toEqual('SAMEORIGIN')
68
- expect(res.headers.get('Strict-Transport-Security')).toEqual(
69
- 'max-age=15552000; includeSubDomains'
70
- )
71
- expect(res.headers.get('X-Download-Options')).toEqual('noopen')
72
- expect(res.headers.get('X-XSS-Protection')).toEqual('0')
73
- expect(res.headers.get('X-Powered-By')).toBeNull()
74
- expect(res.headers.get('X-DNS-Prefetch-Control')).toEqual('off')
75
- expect(res.headers.get('X-Content-Type-Options')).toEqual('nosniff')
76
- expect(res.headers.get('Referrer-Policy')).toEqual('no-referrer')
77
- expect(res.headers.get('X-Permitted-Cross-Domain-Policies')).toEqual('none')
78
- expect(res.headers.get('Cross-Origin-Resource-Policy')).toEqual('same-origin')
79
- expect(res.headers.get('Cross-Origin-Opener-Policy')).toEqual('same-origin')
80
- expect(res.headers.get('Origin-Agent-Cluster')).toEqual('?1')
81
- expect(res.headers.get('Cross-Origin-Embedder-Policy')).toEqual('require-corp')
82
- expect(res.headers.get('Permissions-Policy')).toEqual('camera=()')
83
- expect(res.headers.get('Content-Security-Policy')).toEqual("default-src 'self'")
84
- expect(res.headers.get('Content-Security-Policy-Report-Only')).toEqual("default-src 'self'")
85
- })
86
-
87
- it('specific headers disabled', async () => {
88
- const app = new Acryl()
89
- app.use('*', secureHeaders({ xFrameOptions: false, xXssProtection: false }))
90
- app.get('/test', async (ctx) => {
91
- return ctx.text('test')
92
- })
93
-
94
- const res = await app.request('/test')
95
- expect(res).not.toBeNull()
96
- expect(res.status).toBe(200)
97
- expect(res.headers.get('X-Frame-Options')).toBeNull()
98
- expect(res.headers.get('Strict-Transport-Security')).toEqual(
99
- 'max-age=15552000; includeSubDomains'
100
- )
101
- expect(res.headers.get('X-Download-Options')).toEqual('noopen')
102
- expect(res.headers.get('X-XSS-Protection')).toBeNull()
103
- expect(res.headers.get('X-Powered-By')).toBeNull()
104
- expect(res.headers.get('X-DNS-Prefetch-Control')).toEqual('off')
105
- expect(res.headers.get('X-Content-Type-Options')).toEqual('nosniff')
106
- expect(res.headers.get('Referrer-Policy')).toEqual('no-referrer')
107
- expect(res.headers.get('X-Permitted-Cross-Domain-Policies')).toEqual('none')
108
- expect(res.headers.get('Cross-Origin-Resource-Policy')).toEqual('same-origin')
109
- expect(res.headers.get('Cross-Origin-Opener-Policy')).toEqual('same-origin')
110
- expect(res.headers.get('Permissions-Policy')).toBeNull()
111
- expect(res.headers.get('Origin-Agent-Cluster')).toEqual('?1')
112
- })
113
-
114
- it('should remove x-powered-by header', async () => {
115
- const appBefore = new Acryl()
116
- appBefore.use('*', secureHeaders())
117
- appBefore.use('*', poweredBy())
118
-
119
- const resBefore = await appBefore.request('/')
120
- expect(resBefore.headers.get('x-powered-by')).toBeFalsy()
121
-
122
- const appAfter = new Acryl()
123
- appAfter.use('*', poweredBy())
124
- appAfter.use('*', secureHeaders())
125
-
126
- const resAfter = await appAfter.request('/')
127
- expect(resAfter.headers.get('x-powered-by')).toBe('Acryl')
128
- })
129
-
130
- it('should override Strict-Transport-Security header after middleware', async () => {
131
- const app = new Acryl()
132
- app.use('/test1', secureHeaders())
133
-
134
- app.all('*', async (c) => {
135
- c.res.headers.set('Strict-Transport-Security', 'Acryl')
136
- return c.text('header updated')
137
- })
138
-
139
- const res1 = await app.request('/test1')
140
- expect(res1.headers.get('Strict-Transport-Security')).toEqual(
141
- 'max-age=15552000; includeSubDomains'
142
- )
143
-
144
- const res2 = await app.request('/test2')
145
- expect(res2.headers.get('Strict-Transport-Security')).toEqual('Acryl')
146
- })
147
-
148
- it('should use custom value when overridden', async () => {
149
- const app = new Acryl()
150
- app.use(
151
- '/test',
152
- secureHeaders({
153
- strictTransportSecurity: 'max-age=31536000; includeSubDomains; preload;',
154
- xFrameOptions: 'DENY',
155
- xXssProtection: '1',
156
- })
157
- )
158
-
159
- const res = await app.request('/test')
160
- expect(res.headers.get('Strict-Transport-Security')).toEqual(
161
- 'max-age=31536000; includeSubDomains; preload;'
162
- )
163
- expect(res.headers.get('X-FRAME-OPTIONS')).toEqual('DENY')
164
- expect(res.headers.get('X-XSS-Protection')).toEqual('1')
165
- })
166
-
167
- it('should set Permission-Policy header correctly', async () => {
168
- const app = new Acryl()
169
- app.use(
170
- '/test',
171
- secureHeaders({
172
- permissionsPolicy: {
173
- fullscreen: ['self'],
174
- bluetooth: ['none'],
175
- payment: ['self', 'example.com'],
176
- syncXhr: [],
177
- camera: false,
178
- microphone: true,
179
- geolocation: ['*'],
180
- usb: ['self', 'https://a.example.com', 'https://b.example.com'],
181
- accelerometer: ['https://*.example.com'],
182
- gyroscope: ['src'],
183
- magnetometer: ['https://a.example.com', 'https://b.example.com'],
184
- mediasession: ['self'],
185
- deferredFetch: ['none'],
186
- },
187
- })
188
- )
189
-
190
- const res = await app.request('/test')
191
- expect(res.headers.get('Permissions-Policy')).toEqual(
192
- 'fullscreen=(self), bluetooth=(), payment=(self "example.com"), sync-xhr=(), camera=(), microphone=*, ' +
193
- 'geolocation=*, usb=(self "https://a.example.com" "https://b.example.com"), ' +
194
- 'accelerometer=("https://*.example.com"), gyroscope=(src), ' +
195
- 'magnetometer=("https://a.example.com" "https://b.example.com"), ' +
196
- 'mediasession=(self), deferred-fetch=()'
197
- )
198
- })
199
-
200
- it('Remove X-Powered-By', async () => {
201
- const app = new Acryl()
202
-
203
- app.get('/test', secureHeaders(), poweredBy(), async (c) => {
204
- return c.text('Acryl is hot')
205
- })
206
-
207
- app.get(
208
- '/test2',
209
- secureHeaders({
210
- removePoweredBy: false,
211
- }),
212
- poweredBy(),
213
- async (c) => {
214
- return c.text('Acryl is hot')
215
- }
216
- )
217
-
218
- const res = await app.request('/test')
219
- const poweredby = res.headers.get('X-Powered-By')
220
- expect(poweredby).toEqual(null)
221
- expect(await res.text()).toEqual('Acryl is hot')
222
-
223
- const res2 = await app.request('/test2')
224
- const poweredby2 = res2.headers.get('X-Powered-By')
225
- expect(poweredby2).toEqual('Acryl')
226
- expect(await res2.text()).toEqual('Acryl is hot')
227
- })
228
-
229
- describe.each([
230
- { cspSettingName: 'contentSecurityPolicy', cspHeaderName: 'Content-Security-Policy' },
231
- {
232
- cspSettingName: 'contentSecurityPolicyReportOnly',
233
- cspHeaderName: 'Content-Security-Policy-Report-Only',
234
- },
235
- ])('CSP Setting ($cspSettingName)', ({ cspSettingName, cspHeaderName }) => {
236
- it('CSP Setting', async () => {
237
- const app = new Acryl()
238
- app.use(
239
- '/test',
240
- secureHeaders({
241
- [cspSettingName]: {
242
- defaultSrc: ["'self'"],
243
- baseUri: ["'self'"],
244
- fontSrc: ["'self'", 'https:', 'data:'],
245
- frameAncestors: ["'self'"],
246
- imgSrc: ["'self'", 'data:'],
247
- objectSrc: ["'none'"],
248
- scriptSrc: ["'self'"],
249
- scriptSrcAttr: ["'none'"],
250
- styleSrc: ["'self'", 'https:', "'unsafe-inline'"],
251
- requireTrustedTypesFor: ["'script'"],
252
- trustedTypes: ["'none'"],
253
- },
254
- })
255
- )
256
-
257
- app.all('*', async (c) => {
258
- c.res.headers.set('Strict-Transport-Security', 'Acryl')
259
- return c.text('header updated')
260
- })
261
-
262
- const res = await app.request('/test')
263
- expect(res.headers.get(cspHeaderName)).toEqual(
264
- "default-src 'self'; base-uri 'self'; font-src 'self' https: data:; frame-ancestors 'self'; img-src 'self' data:; object-src 'none'; script-src 'self'; script-src-attr 'none'; style-src 'self' https: 'unsafe-inline'; require-trusted-types-for 'script'; trusted-types 'none'"
265
- )
266
- })
267
-
268
- it('CSP Setting one only', async () => {
269
- const app = new Acryl()
270
- app.use(
271
- '/test',
272
- secureHeaders({
273
- [cspSettingName]: {
274
- defaultSrc: ["'self'"],
275
- },
276
- })
277
- )
278
-
279
- app.all('*', async (c) => {
280
- return c.text('header updated')
281
- })
282
-
283
- const res = await app.request('/test')
284
- expect(res.headers.get(cspHeaderName)).toEqual("default-src 'self'")
285
- })
286
-
287
- it('No CSP Setting', async () => {
288
- const app = new Acryl()
289
- app.use('/test', secureHeaders({ [cspSettingName]: {} }))
290
-
291
- app.all('*', async (c) => {
292
- return c.text('header updated')
293
- })
294
-
295
- const res = await app.request('/test')
296
- expect(res.headers.get(cspHeaderName)).toEqual('')
297
- })
298
-
299
- it('CSP with reportTo', async () => {
300
- const app = new Acryl()
301
- app.use(
302
- '/test1',
303
- secureHeaders({
304
- reportingEndpoints: [
305
- {
306
- name: 'endpoint-1',
307
- url: 'https://example.com/reports',
308
- },
309
- ],
310
- [cspSettingName]: {
311
- defaultSrc: ["'self'"],
312
- reportTo: 'endpoint-1',
313
- },
314
- })
315
- )
316
-
317
- app.use(
318
- '/test2',
319
- secureHeaders({
320
- reportTo: [
321
- {
322
- group: 'endpoint-1',
323
- max_age: 10886400,
324
- endpoints: [{ url: 'https://example.com/reports' }],
325
- },
326
- ],
327
- [cspSettingName]: {
328
- defaultSrc: ["'self'"],
329
- reportTo: 'endpoint-1',
330
- },
331
- })
332
- )
333
-
334
- app.use(
335
- '/test3',
336
- secureHeaders({
337
- reportTo: [
338
- {
339
- group: 'g1',
340
- max_age: 10886400,
341
- endpoints: [
342
- { url: 'https://a.example.com/reports' },
343
- { url: 'https://b.example.com/reports' },
344
- ],
345
- },
346
- {
347
- group: 'g2',
348
- max_age: 10886400,
349
- endpoints: [
350
- { url: 'https://c.example.com/reports' },
351
- { url: 'https://d.example.com/reports' },
352
- ],
353
- },
354
- ],
355
- [cspSettingName]: {
356
- defaultSrc: ["'self'"],
357
- reportTo: 'g2',
358
- },
359
- })
360
- )
361
-
362
- app.use(
363
- '/test4',
364
- secureHeaders({
365
- reportingEndpoints: [
366
- {
367
- name: 'e1',
368
- url: 'https://a.example.com/reports',
369
- },
370
- {
371
- name: 'e2',
372
- url: 'https://b.example.com/reports',
373
- },
374
- ],
375
- [cspSettingName]: {
376
- defaultSrc: ["'self'"],
377
- reportTo: 'e1',
378
- },
379
- })
380
- )
381
-
382
- app.all('*', async (c) => {
383
- return c.text('header updated')
384
- })
385
-
386
- const res1 = await app.request('/test1')
387
- expect(res1.headers.get('Reporting-Endpoints')).toEqual(
388
- 'endpoint-1="https://example.com/reports"'
389
- )
390
- expect(res1.headers.get(cspHeaderName)).toEqual("default-src 'self'; report-to endpoint-1")
391
-
392
- const res2 = await app.request('/test2')
393
- expect(res2.headers.get('Report-To')).toEqual(
394
- '{"group":"endpoint-1","max_age":10886400,"endpoints":[{"url":"https://example.com/reports"}]}'
395
- )
396
- expect(res2.headers.get(cspHeaderName)).toEqual("default-src 'self'; report-to endpoint-1")
397
-
398
- const res3 = await app.request('/test3')
399
- expect(res3.headers.get('Report-To')).toEqual(
400
- '{"group":"g1","max_age":10886400,"endpoints":[{"url":"https://a.example.com/reports"},{"url":"https://b.example.com/reports"}]}, {"group":"g2","max_age":10886400,"endpoints":[{"url":"https://c.example.com/reports"},{"url":"https://d.example.com/reports"}]}'
401
- )
402
- expect(res3.headers.get(cspHeaderName)).toEqual("default-src 'self'; report-to g2")
403
-
404
- const res4 = await app.request('/test4')
405
- expect(res4.headers.get('Reporting-Endpoints')).toEqual(
406
- 'e1="https://a.example.com/reports", e2="https://b.example.com/reports"'
407
- )
408
- expect(res4.headers.get(cspHeaderName)).toEqual("default-src 'self'; report-to e1")
409
- })
410
-
411
- it('CSP nonce for script-src', async () => {
412
- const app = new Acryl()
413
- app.use(
414
- '/test',
415
- secureHeaders({
416
- [cspSettingName]: {
417
- scriptSrc: ["'self'", NONCE],
418
- },
419
- })
420
- )
421
-
422
- app.all('*', async (c) => {
423
- return c.text(`nonce: ${c.get('secureHeadersNonce')}`)
424
- })
425
-
426
- const res = await app.request('/test')
427
- const csp = res.headers.get(cspHeaderName)
428
- const nonce = csp?.match(/script-src 'self' 'nonce-([a-zA-Z0-9+/]+=*)'/)?.[1] || ''
429
- expect(csp).toMatch(`script-src 'self' 'nonce-${nonce}'`)
430
- expect(await res.text()).toEqual(`nonce: ${nonce}`)
431
- })
432
-
433
- it('CSP nonce for script-src and style-src', async () => {
434
- const app = new Acryl()
435
- app.use(
436
- '/test',
437
- secureHeaders({
438
- [cspSettingName]: {
439
- scriptSrc: ["'self'", NONCE],
440
- styleSrc: ["'self'", NONCE],
441
- },
442
- })
443
- )
444
-
445
- app.all('*', async (c) => {
446
- return c.text(`nonce: ${c.get('secureHeadersNonce')}`)
447
- })
448
-
449
- const res = await app.request('/test')
450
- const csp = res.headers.get(cspHeaderName)
451
- const nonce = csp?.match(/script-src 'self' 'nonce-([a-zA-Z0-9+/]+=*)'/)?.[1] || ''
452
- expect(csp).toMatch(`script-src 'self' 'nonce-${nonce}'`)
453
- expect(csp).toMatch(`style-src 'self' 'nonce-${nonce}'`)
454
- expect(await res.text()).toEqual(`nonce: ${nonce}`)
455
- })
456
-
457
- it('CSP nonce by app own function', async () => {
458
- const app = new Acryl()
459
- const setNonce: ContentSecurityPolicyOptionHandler = (ctx, directive) => {
460
- ctx.set(`test-${directive}-nonce`, directive)
461
- return `'nonce-${directive}'`
462
- }
463
- app.use(
464
- '/test',
465
- secureHeaders({
466
- [cspSettingName]: {
467
- scriptSrc: ["'self'", setNonce],
468
- styleSrc: ["'self'", setNonce],
469
- },
470
- })
471
- )
472
-
473
- app.all('*', async (c) => {
474
- return c.text(
475
- `script: ${c.get('test-scriptSrc-nonce')}, style: ${c.get('test-styleSrc-nonce')}`
476
- )
477
- })
478
-
479
- const res = await app.request('/test')
480
- const csp = res.headers.get(cspHeaderName)
481
- expect(csp).toMatch("script-src 'self' 'nonce-scriptSrc'")
482
- expect(csp).toMatch("style-src 'self' 'nonce-styleSrc'")
483
- expect(await res.text()).toEqual('script: scriptSrc, style: styleSrc')
484
- })
485
- })
486
-
487
- describe('CSP with combined modes', () => {
488
- it('keeps the enforced policy when report-only uses a nonce', async () => {
489
- const app = new Acryl()
490
- app.use(
491
- '/test',
492
- secureHeaders({
493
- contentSecurityPolicy: {
494
- defaultSrc: ["'self'"],
495
- },
496
- contentSecurityPolicyReportOnly: {
497
- scriptSrc: ["'self'", NONCE],
498
- },
499
- })
500
- )
501
- app.all('*', (c) => c.text('test'))
502
-
503
- const res = await app.request('/test')
504
-
505
- expect(res.status).toBe(200)
506
- expect(res.headers.get('Content-Security-Policy')).toBe("default-src 'self'")
507
- expect(res.headers.get('Content-Security-Policy-Report-Only')).toMatch(
508
- /^script-src 'self' 'nonce-[a-zA-Z0-9+/]+=*'$/
509
- )
510
- })
511
-
512
- it('keeps the report-only policy when the enforced policy uses a nonce', async () => {
513
- const app = new Acryl()
514
- app.use(
515
- '/test',
516
- secureHeaders({
517
- contentSecurityPolicy: {
518
- scriptSrc: ["'self'", NONCE],
519
- },
520
- contentSecurityPolicyReportOnly: {
521
- defaultSrc: ["'self'"],
522
- },
523
- })
524
- )
525
- app.all('*', (c) => c.text('test'))
526
-
527
- const res = await app.request('/test')
528
-
529
- expect(res.status).toBe(200)
530
- expect(res.headers.get('Content-Security-Policy')).toMatch(
531
- /^script-src 'self' 'nonce-[a-zA-Z0-9+/]+=*'$/
532
- )
533
- expect(res.headers.get('Content-Security-Policy-Report-Only')).toBe("default-src 'self'")
534
- })
535
-
536
- it('supports nonces in both policies', async () => {
537
- const app = new Acryl()
538
- app.use(
539
- '/test',
540
- secureHeaders({
541
- contentSecurityPolicy: {
542
- scriptSrc: ["'self'", NONCE],
543
- },
544
- contentSecurityPolicyReportOnly: {
545
- styleSrc: ["'self'", NONCE],
546
- },
547
- })
548
- )
549
- app.all('*', (c) => c.text('test'))
550
-
551
- const res = await app.request('/test')
552
- const csp = res.headers.get('Content-Security-Policy')
553
- const reportOnly = res.headers.get('Content-Security-Policy-Report-Only')
554
- const nonce = csp?.match(/'nonce-([^']+)'/)?.[1]
555
-
556
- expect(res.status).toBe(200)
557
- expect(nonce).toBeTruthy()
558
- expect(reportOnly).toContain(`'nonce-${nonce}'`)
559
- })
560
- })
561
-
562
- // OUR NEW REPORT-URI TESTS
563
- describe('CSP report-uri directive', () => {
564
- it('should set report-uri with single endpoint', async () => {
565
- const app = new Acryl()
566
- app.use(
567
- '/test',
568
- secureHeaders({
569
- contentSecurityPolicy: {
570
- defaultSrc: ["'self'"],
571
- reportUri: '/csp-report',
572
- },
573
- })
574
- )
575
-
576
- const res = await app.request('/test')
577
- expect(res.headers.get('Content-Security-Policy')).toEqual(
578
- "default-src 'self'; report-uri /csp-report"
579
- )
580
- })
581
-
582
- it('should set report-uri with multiple endpoints', async () => {
583
- const app = new Acryl()
584
- app.use(
585
- '/test',
586
- secureHeaders({
587
- contentSecurityPolicy: {
588
- defaultSrc: ["'self'"],
589
- reportUri: ['/endpoint1', '/endpoint2'],
590
- },
591
- })
592
- )
593
-
594
- const res = await app.request('/test')
595
- expect(res.headers.get('Content-Security-Policy')).toEqual(
596
- "default-src 'self'; report-uri /endpoint1 /endpoint2"
597
- )
598
- })
599
-
600
- it('should work with report-to and report-uri together', async () => {
601
- const app = new Acryl()
602
- app.use(
603
- '/test',
604
- secureHeaders({
605
- contentSecurityPolicy: {
606
- defaultSrc: ["'self'"],
607
- reportTo: 'endpoint-1',
608
- reportUri: '/legacy-report',
609
- },
610
- })
611
- )
612
-
613
- const res = await app.request('/test')
614
- expect(res.headers.get('Content-Security-Policy')).toEqual(
615
- "default-src 'self'; report-to endpoint-1; report-uri /legacy-report"
616
- )
617
- })
618
-
619
- it('should work with Content-Security-Policy-Report-Only', async () => {
620
- const app = new Acryl()
621
- app.use(
622
- '/test',
623
- secureHeaders({
624
- contentSecurityPolicyReportOnly: {
625
- defaultSrc: ["'self'"],
626
- reportUri: '/csp-report-only',
627
- },
628
- })
629
- )
630
-
631
- const res = await app.request('/test')
632
- expect(res.headers.get('Content-Security-Policy-Report-Only')).toEqual(
633
- "default-src 'self'; report-uri /csp-report-only"
634
- )
635
- })
636
-
637
- // ADDED MISSING TEST CASE for Report-Only:
638
-
639
- it('should not output report-uri when reportUri is not set', async () => {
640
- const app = new Acryl()
641
- app.use(
642
- '/test',
643
- secureHeaders({
644
- contentSecurityPolicy: {
645
- defaultSrc: ["'self'"],
646
- },
647
- })
648
- )
649
-
650
- const res = await app.request('/test')
651
- const header = res.headers.get('Content-Security-Policy') || ''
652
- expect(header.includes('report-uri')).toBe(false)
653
- })
654
-
655
- it('should not output report-uri in Report-Only when reportUri is not set', async () => {
656
- const app = new Acryl()
657
- app.use(
658
- '/test',
659
- secureHeaders({
660
- contentSecurityPolicyReportOnly: {
661
- defaultSrc: ["'self'"],
662
- },
663
- })
664
- )
665
-
666
- const res = await app.request('/test')
667
- const header = res.headers.get('Content-Security-Policy-Report-Only') || ''
668
- expect(header.includes('report-uri')).toBe(false)
669
- })
670
- })
671
- })