Browse Source

Merge pull request #317 from james2doyle/feature/try-with-cors

Added: support for csrf tokens that apply automatically
Shalvah 3 years ago
parent
commit
84265710f0
3 changed files with 48 additions and 3 deletions
  1. 17 0
      config/scribe.php
  2. 28 3
      resources/js/tryitout.js
  3. 3 0
      resources/views/themes/default/index.blade.php

+ 17 - 0
config/scribe.php

@@ -185,6 +185,23 @@ return [
          * Leave as null to use the current app URL (config(app.url)).
          */
         'base_url' => null,
+
+        /**
+         * Fetch the CSRF token before each request. This is required if you are using Laravel Sanctum
+         */
+        'use_csrf' => false,
+
+        /**
+         * The URL to set the sessions CSRF token for the application
+         * Only used when 'use_csrf' is not set to false
+         */
+        'csrf_url' => '/sanctum/csrf-token',
+
+        /**
+         * The name of the cookie to set when making requests
+         * Only used when 'use_csrf' is not set to false
+         */
+        'csrf_cookie_name' => 'X-XSRF-TOKEN',
     ],
 
     /*

+ 28 - 3
resources/js/tryitout.js

@@ -1,5 +1,21 @@
 window.abortControllers = {};
 
+function getCookie(name) {
+    if (!document.cookie) {
+        return null;
+    }
+
+    const xsrfCookies = document.cookie.split(';')
+        .map(c => c.trim())
+        .filter(c => c.startsWith(name + '='));
+
+    if (xsrfCookies.length === 0) {
+        return null;
+    }
+
+    return decodeURIComponent(xsrfCookies[0].split('=')[1]);
+}
+
 function tryItOut(endpointId) {
     document.querySelector(`#btn-tryout-${endpointId}`).hidden = true;
     document.querySelector(`#btn-executetryout-${endpointId}`).hidden = false;
@@ -81,7 +97,10 @@ function makeAPICall(method, path, body, query, headers, endpointId) {
         method,
         headers,
         body: method === 'GET' ? undefined : body,
-        signal: window.abortControllers[endpointId].signal
+        signal: window.abortControllers[endpointId].signal,
+        referrer: window.baseUrl,
+        mode: 'cors',
+        credentials: 'same-origin',
     })
         .then(response => Promise.all([response.status, response.text(), response.headers]));
 }
@@ -178,7 +197,7 @@ async function executeTryOut(endpointId, form) {
     const query = {};
     const queryParameters = form.querySelectorAll('input[data-component=query]');
     queryParameters.forEach(el => _.set(query, el.name, el.value));
-    
+
     // Group radio buttons by their name, and then set the checked value from that group
     Array.from(queryParameters)
         .filter(el => el.type === "radio")
@@ -216,7 +235,13 @@ async function executeTryOut(endpointId, form) {
         }
     }
 
-    makeAPICall(method, path, body, query, headers, endpointId)
+    const preflightPromise = window.useCsrf && window.csrfUrl ? makeAPICall('GET', window.csrfUrl, {}, {}, {}, null).then(() => {
+            headers['X-XSRF-TOKEN'] = getCookie(window.csrfCookieName);
+
+            return makeAPICall(method, path, body, query, headers, endpointId);
+        }) : makeAPICall(method, path, body, query, headers, endpointId);
+
+    preflightPromise
         .then(([responseStatus, responseContent, responseHeaders]) => {
             handleResponse(endpointId, responseContent, responseStatus, responseHeaders)
         })

+ 3 - 0
resources/views/themes/default/index.blade.php

@@ -24,6 +24,9 @@
     <script src="//cdn.jsdelivr.net/npm/lodash@4.17.10/lodash.min.js"></script>
     <script>
         var baseUrl = "{{ $tryItOut['base_url'] ?? config('app.url') }}";
+        var useCsrf = Boolean({{ $tryItOut['use_csrf'] ?? null }});
+        var csrfUrl = "{{ $tryItOut['csrf_url'] ?? null }}";
+        var csrfCookieName = "{{ $tryItOut['csrf_cookie_name'] ?? "XSRF-TOKEN" }}";
     </script>
     <script src="{{ u::getVersionedAsset($assetPathPrefix.'js/tryitout.js') }}"></script>
 @endif