[Fixed] Accordion Collapsible Does not work only in Heroku (CSP Issue)

Issue

Iam facing a very strange issue. I implemented some nested collapsible and also simple collapsible that work excellent at localhost.But in Heroku still i cannot understand why collapsibles do not work. Any help is welcomed, without working collapsible my web app will appear chaotic 🙁

Pug Layout

doctype html
html(lang='en')
    head
        title= title
        meta(charset='utf-8')
        meta(name='viewport', content='width=device-width, initial-scale=1')
        script(src="https://code.jquery.com/jquery-3.5.1.slim.min.js", integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj", crossorigin="anonymous")
        link(rel="stylesheet", href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css", integrity="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z", crossorigin="anonymous")
        script(src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js", integrity="sha384-B4gt1jrGC7Jh4AgTPSdUtOBvfO8shuf57BaghqFfPlYxofvL8/KUEfYiJOMMV+rV", crossorigin="anonymous")
        link(rel='stylesheet', href='/stylesheets/style.css')
    body
    div(class='container-fluid')
      div(class='row')
        div(class='col-sm-2')
          block sidebar
            ul(class='sidebar-nav')
              li
                a(href='/catalog') Home
              li
                a(href='/catalog/resources') All Resources

              li
                a(href='/catalog/bookings') My Bookings
        div(class='col-sm-10')
          block content

Collapsible PUG

extends layout
block content
  -var i=0;
  -var months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]
        #accordion.panel-group
        each doc in object
           flex-container(style='background-color:#c7e7fa; justify-content:space-around; position:relative;flex-direction:row;margin-left:20px;margin-right:auto; margin-top:20px; width:45%; ')
            .three(style='text-align:center;margin-left:auto; margin-right:auto; flex: 0 0 40%;')
              h4='' + doc._id.year + '  ' + months[doc._id.month - 1]
              -i++;
            #accordion.panel-group
             .panel-heading
               h4.panel-title
                 a.accordion-toggle(data-toggle='collapse', href='#collapses' + i)
                   h6 See Total Cost
             .panel-collapse.collapse.in(id="collapses" + i)
                .three(style='width:100%; margin-left:auto; margin-right:auto; flex: 0 0 25%;')
                  h5= 'Total Montly Cost:  ' + doc.total_cost_month.toFixed(2)
                                .panel-heading
                                  h4.panel-title
                                    a.accordion-toggle(data-toggle='collapse', href='#collapse'+i)
                                      hr
                                      h6 See All Booking details
                                .panel-collapse.collapse.in(id="collapse"+i)
                                  each booking in doc.bookings_month
                                    flex-container(style='background-color:#a6f1a6; width:100%;')
                                                three.flex-container
                                                    | #[strong Start:] #{moment(booking.date_started).format('DD/MM/YYYY HH:mm')}
                                                three.flex-container
                                                    | #[strong  Finish:] #{moment(booking.date_finished).format('DD/MM/YYYY HH:mm')}
                                                three.flex-container
                                                    | #[strong  Cost:]  #{booking.total_cost.toFixed(2)}
                                                li
        else
            h1 No booking history found
            h3= 'Start booking now' + "  "
             a(href='/catalog/resources')
              | here:

Solution

So it’s solved . The problem sources from the server-side. Especially from helmetjs, app.use(helmet()). So helmet by default blocks every content like script stylesheets and multimedia links that are loading in the pug views, in order to prevent XSS attacks. So what we have to do, is to tell helmet that we want to whitelist some link references, which could be a stylesheet link, a script link and image link etc. We do that by including in our code (app.js) this code fragment.

app.use(helmet({
  contentSecurityPolicy:{
    directives:{
      "default-src":["'self'"],
      "script-src":["https://code.jquery.com/jquery-3.5.1.slim.min.js","'sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj'","https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js","'sha384-B4gt1jrGC7Jh4AgTPSdUtOBvfO8shuf57BaghqFfPlYxofvL8/KUEfYiJOMMV+rV'"],
      "style-src": ["'self'","https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css","'unsafe-inline'"],
      "object-src":["'none'"],


    },
  }
}
));

So helmet is a module that we have already imported in our app. This module has some properties. In our issue we focus on the property contentSecurityPolicy, cause we need to solve a CSP problem. To put some exceptions we add them inside directives property.These exceptions are key-value pairs, where key is the type of the content that will be loaded in our web app and the value is the actual link that carries the content. So now we will adress the solution, be carefull at the order of the properties because that is very important. "default-src":["'self'"] is the by default property and we tell web app to load content only from its domain 'self'.
Next comes the "script-src", this is our jquery script with the hash taken from our layoyt above and also the script that uses our bootstrap stylesheet, and this has also its hash. Then it is "style-src" which is the actual bootstrap template, we add 'self' (iam not pretty sure if self is not optional) and then we use "'unsafe-inline'" which means that our app loads the hash that exist in each particular pug template. Finally "object-src" is a property we should assign as "'none'".
So thats it be carefull about the order of the commands

Leave a Reply

(*) Required, Your email will not be published