headers.ts 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
  1. import type { Response } from 'express';
  2. import type { ExpressHttpHeader, IContentHeaders } from '~/server/interfaces/attachment';
  3. import type { IAttachmentDocument } from '~/server/models/attachment';
  4. export class ContentHeaders implements IContentHeaders {
  5. contentType?: ExpressHttpHeader<'Content-Type'>;
  6. contentLength?: ExpressHttpHeader<'Content-Length'>;
  7. contentSecurityPolicy?: ExpressHttpHeader<'Content-Security-Policy'>;
  8. contentDisposition?: ExpressHttpHeader<'Content-Disposition'>;
  9. constructor(attachment: IAttachmentDocument, opts?: {
  10. inline?: boolean,
  11. }) {
  12. this.contentType = {
  13. field: 'Content-Type',
  14. value: attachment.fileFormat,
  15. };
  16. this.contentSecurityPolicy = {
  17. field: 'Content-Security-Policy',
  18. // eslint-disable-next-line max-len
  19. value: "script-src 'unsafe-hashes'; style-src 'self' 'unsafe-inline'; object-src 'none'; require-trusted-types-for 'script'; media-src 'self'; default-src 'none';",
  20. };
  21. this.contentDisposition = {
  22. field: 'Content-Disposition',
  23. value: `${opts?.inline ? 'inline' : 'attachment'};filename*=UTF-8''${encodeURIComponent(attachment.originalName)}`,
  24. };
  25. if (attachment.fileSize) {
  26. this.contentLength = {
  27. field: 'Content-Length',
  28. value: attachment.fileSize.toString(),
  29. };
  30. }
  31. }
  32. /**
  33. * Convert to ExpressHttpHeader[]
  34. */
  35. toExpressHttpHeaders(): ExpressHttpHeader[] {
  36. return [
  37. this.contentType,
  38. this.contentLength,
  39. this.contentSecurityPolicy,
  40. this.contentDisposition,
  41. ]
  42. // exclude undefined
  43. .filter((member): member is NonNullable<typeof member> => member != null);
  44. }
  45. }
  46. /**
  47. * Convert Record to ExpressHttpHeader[]
  48. */
  49. export const toExpressHttpHeaders = (records: Record<string, string | string[]>): ExpressHttpHeader[] => {
  50. return Object.entries(records).map(([field, value]) => { return { field, value } });
  51. };
  52. export const applyHeaders = (res: Response, headers: ExpressHttpHeader[]): void => {
  53. headers.forEach((header) => {
  54. res.header(header.field, header.value);
  55. });
  56. };