Skip to content

Any way to avoid converting fonts to text? #2

@brycewray

Description

@brycewray

I already had a CF Worker that added a number of headers, and wanted to employ yours also for adding/handling nonces for CSP. Of course, you can't use two workers on the same route, so I ended up trying to combine mine and yours. The following Frankenstein's monster is the result. It does everything I want except that the use of html in the closing return ends up corrupting a downloaded web font (Failed to convert WOFF 2.0 font to SFNT). I know I probably screwed up something, and would appreciate any thoughts you might have on how I could resolve that one problem. Thanks for the script!

addEventListener('fetch', event => {
  event.respondWith(handleRequest(event.request))
})

/* ====================================
nonce for CSP . . .
based on https://github.com/moveyourdigital/cloudflare-worker-csp-nonce
as of 2021-08-25
==================================== */

function dec2hex(dec) {
  return ("0" + dec.toString(16)).substr(-2)
}

function generateNonce() {
  const arr = new Uint8Array(12)
  crypto.getRandomValues(arr)
  const values = Array.from(arr, dec2hex)
  return [
    btoa(values.slice(0, 5).join("")).substr(0, 14),
    btoa(values.slice(5).join("")),
  ].join("/")
}

/**
 * Respond to the request
 * @param {Request} request
 */

async function handleRequest(request) {
  const nonce = generateNonce()
  const originresponse = await fetch(request, {
    redirect: "manual",
  })

  let clone = originresponse.clone()
  // https://stackoverflow.com/questions/40497859/reread-a-response-body-from-javascripts-fetch

  const html = (await originresponse.text())
    .replace(/DhcnhD3khTMePgXw/gi, nonce)
    .replace(
      'src="https://ajax.cloudflare.com',
      `nonce="${nonce}" src="https://ajax.cloudflare.com`
    )
    .replace(
      'src="https://static.cloudflareinsights.com',
      `nonce="${nonce}" src="https://static.cloudflareinsights.com`
    )
    .replace(
      'cloudflare-static/email-decode.min.js"',
      `cloudflare-static/email-decode.min.js" nonce="${nonce}"`
    )

  let ttl = undefined
  let cache = caches.default
  let url = new URL(request.url)
  let shouldCache = false
  let jsStuff = false
  let svgStuff = false

  const filesRegex = /(.*\.(ac3|avi|bmp|br|bz2|css|cue|dat|doc|docx|dts|eot|exe|flv|gif|gz|ico|img|iso|jpeg|jpg|js|json|map|mkv|mp3|mp4|mpeg|mpg|ogg|pdf|png|ppt|pptx|qt|rar|rm|svg|swf|tar|tgz|ttf|txt|wav|webp|webm|webmanifest|woff|woff2|xls|xlsx|xml|zip))$/
  const jsRegex = /(.*\.(js))$/
  const svgRegex = /(.*\.(svg))$/

  if (url.pathname.match(filesRegex)) {
    shouldCache = true
    ttl = 31536000
  }
  if (url.pathname.match(jsRegex)) {
    jsStuff = true
  }
  if (url.pathname.match(svgRegex)) {
    svgStuff = true
  }

  let newHeaders = new Headers(originresponse.headers)
  newHeaders.set("Cache-Control", "public, max-age=0")
  // newHeaders.set("Permissions-Policy", "interest-cohort=()")
  newHeaders.set("Strict-Transport-Security", "max-age=63072000; includeSubDomains; preload")
  newHeaders.set("X-Frame-Options", "SAMEORIGIN")
  newHeaders.set("X-Content-Type-Options", "nosniff")
  newHeaders.set("Referrer-Policy", "no-referrer, strict-origin-when-cross-origin")
  if (ttl) {
    newHeaders.set("Cache-Control", "public, max-age=" + ttl + ", immutable")
    newHeaders.set("CDN-Cache-Control", "public, max-age=" + ttl + ", immutable")
  } else {
    newHeaders.set("Content-Security-Policy-Report-Only", `default-src 'none'; report-uri https://brycewray.report-uri.com/r/d/csp/reportOnly; connect-src 'self'; base-uri 'self'; frame-src  'self' https://*.brycewray.com https://*.youtube-nocookie.com; frame-ancestors 'self' https://*.brycewray.com https://*.youtube-nocookie.com; form-action 'self'; style-src 'self' https://*.brycewray.com https://*.youtube-nocookie.com data:; img-src 'self' https://*.brycewray.com https://*.cloudinary.com https://*.ytimg.com https://*.ggpht.com https://*.youtube-nocookie.com data:; font-src 'self' https://*.brycewray.com https://*.gstatic.com; script-src 'self' 'nonce-${nonce}' 'strict-dynamic'; script-src-elem 'self' https://*.brycewray.com`)
    newHeaders.set("Report-To", "{'group':'default','max_age':31536000,'endpoints':[{'url':'https://brycewray.report-uri.com/a/d/g'}],'include_subdomains':true}")
    newHeaders.set("X-XSS-Protection", "1")
  }
  newHeaders.set("cf-nonce-generator", "HIT")
  if (jsStuff) {
    newHeaders.set("Content-Type", "application/javascript; charset=utf-8")
  }
  if (svgStuff) {
    newHeaders.set("Content-Type", "image/svg+xml; charset=utf-8")
  }

  return new Response(html, {
    status: originresponse.status,
    statusText: originresponse.statusText,
    headers: newHeaders
  })
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions