~harmless/security.txt

e3973766b955fc68b0e3472d3667011c85ed87ed — Travis Paul 1 year, 8 months ago d79a448
Remove need for localStorage
A .github/workflow/lint.yml => .github/workflow/lint.yml +11 -0
@@ 0,0 1,11 @@
name: Lint
on: [pull_request, push]
jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2
    - name: Install node_modules
      run: yarn
    - name: Lint Node.js
      run:  yarn run lint
\ No newline at end of file

M Gruntfile.js => Gruntfile.js +6 -4
@@ 46,9 46,7 @@ module.exports = function(grunt) {
          jshintrc: '.jshintrc'
        },
        src: [
          'src/js/**.js',
          '!src/js/backgroundScriptsAPIBridge.js',
          '!src/js/contentScriptsAPIBridge.js'
          'src/js/**.js'
        ]
      },
      node: {


@@ 101,9 99,13 @@ module.exports = function(grunt) {
    });
  });

  grunt.registerTask('default', [
  grunt.registerTask('lint', [
    'jshint:extension',
    'jshint:node',
  ]);

  grunt.registerTask('default', [
    'lint',
    'clean',
    'mkdir',
    'manifests',

M package.json => package.json +2 -1
@@ 8,7 8,8 @@
  "author": "Harmless Systems <info@harmless.systems>",
  "license": "BSD-2-Clause",
  "scripts": {
    "build": "node_modules/.bin/grunt"
    "build": "grunt",
    "lint": "grunt lint"
  },
  "devDependencies": {
    "grunt": "^1.0.4",

M src/css/popup.css => src/css/popup.css +2 -1
@@ 4,7 4,8 @@
}
body {
  overflow: hidden;
  min-width:600px;
  min-width: 650px;
  font-size: 11px;
}
.tabs {
  background: #fff;

A src/img/info.128.png => src/img/info.128.png +0 -0
M src/install.html => src/install.html +1 -0
@@ 19,6 19,7 @@
    <footer>
      <p>&copy; <span class="current-year"></span> <a href="https://www.harmless.systems">Harmless Systems</a></p>
    </footer>
    <script src="js/browser-polyfill.js"></script>
    <script src="js/global.js"></script>
    <script src="js/i18n.js"></script>
  </body>

M src/js/background.js => src/js/background.js +20 -32
@@ 16,45 16,34 @@ function fetchError(error) {
function fetchFiles(tabId, tab) {
  const tabURL = new URL(tab.url);
  const host = `${tabURL.protocol}//${tabURL.host}`;
  const fetchOptions = {method: 'HEAD'};

  const finalResults = {
    now: Date.now(),
    host: tabURL.host,
    security: false,
    humans: false
    security: '',
    humans: ''
  };

  let humansTxtCheck = true;

  fetch(`${host}/.well-known/security.txt`).then((result) => {
  fetch(`${host}/.well-known/security.txt`, fetchOptions).then((result) => {

    console.log('/.well-known/security.txt', result.status,
    console.log(`${host}/.well-known/security.txt`, result.status,
      result.headers.get('Content-Type'));

    if (!result.ok || !isPlainText(result)) {

      return fetch(`${host}/security.txt`).then((result) => {
      return fetch(`${host}/security.txt`, fetchOptions).then((result) => {

        console.log('/security.txt', result.status,
        console.log(`${host}/security.txt`, result.status,
          result.headers.get('Content-Type'));

        if (result.ok && isPlainText(result)) {
          result.text().then((text) => {
            finalResults.security = {
              path: `${host}/security.txt`,
              text
            };
          });
          finalResults.security = `${host}/security.txt`;
        }
      }, fetchError);
    }

    return result.text().then((text) => {
      finalResults.security = {
        path: `${host}/.well-known/security.txt`,
        text
      };
    });
    finalResults.security =`${host}/.well-known/security.txt`;

  }, fetchError).finally(() => {



@@ 65,18 54,17 @@ function fetchFiles(tabId, tab) {
        return console.log('humans.txt check disabled');
      }

      return fetch(`${host}/humans.txt`).then((result) => {
      // XXX I've encountered at least one site (netflix.com) where a HEAD 
      // doesn't work on a humans.txt file (403 response). While odd, in all 
      // fairness, the "humans.txt" files is inteded for "humans" who wouldn't
      // be making HEAD requests but rather navigating to the URL manually...
      return fetch(`${host}/humans.txt`/*, fetchOptions*/).then((result) => {

        console.log('/humans.txt', result.status,
        console.log(`${host}/humans.txt`, result.status,
          result.headers.get('Content-Type'));

        if (result.ok && isPlainText(result)) {
          return result.text().then((text) => {
            finalResults.humans = {
              path: `${host}/humans.txt`,
              text
            };
          });
          finalResults.humans = `${host}/humans.txt`;
        }
      }, fetchError);



@@ 92,7 80,7 @@ function fetchFiles(tabId, tab) {
      } else if (finalResults.security && finalResults.humans) {
        title = i18n('found_security_and_humans_txt');
      }
      

      // Mote that we need to change icons for Chrome/Edge bug with pageAction.hide()
      // interesting enough, the bug doesn't impact Opera
      if (finalResults.security || finalResults.humans) {


@@ 100,7 88,8 @@ function fetchFiles(tabId, tab) {
        browser.pageAction.show(tabId);
        browser.pageAction.setPopup({
          tabId: tabId,
          popup: 'popup.html#' + finalResults.host
          popup: `popup.html?security=${finalResults.security}` +
            `&humans=${finalResults.humans}`
        });

        if (BROWSER_QUIRKS === 'chrome' || BROWSER_QUIRKS === 'edge') {


@@ 117,7 106,6 @@ function fetchFiles(tabId, tab) {
          });
        }
      } else {
        localStorage.removeItem(finalResults.host);
        browser.pageAction.hide(tabId);
        browser.pageAction.setPopup({
          tabId: tabId,


@@ 158,7 146,7 @@ function tabsOnUpdated(tabId, changeInfo, tab) {

function runtimeOnInstalled(details) {

  // process each existing tab that's open when the extension is installed
  // Process each existing tab that's open when the extension is installed
  browser.tabs.query({}).then((tabs) => {
    tabs.forEach((tab) => {
      if (httpRegExp.test(tab.url)) {

M src/js/global.js => src/js/global.js +1 -4
@@ 1,15 1,12 @@
/* jshint unused: false */

const defaultOptions = {
  display_mode: 'INLINE',
  check_humanstxt: 'ON',
  color_theme: 'AUTO',
  host_cache_ttl: '24H'
};

function i18n(msg) {
  return ((window.chrome && typeof window.chrome.i18n === 'object') ?
    chrome.i18n.getMessage(msg) : msg) || msg;
  return browser.i18n.getMessage(msg) || msg;
}

const i18nTag = {

M src/js/popup.js => src/js/popup.js +27 -23
@@ 1,7 1,9 @@
/* globals i18n, i18nHydrate */
/* globals i18n, i18nHydrate, URLSearchParams */

window.addEventListener('DOMContentLoaded', () => {
  const host = document.location.hash.replace('#', '');
  const params = new URLSearchParams(new URL(window.location).search);
  console.log('popup', window.location, new URL(window.location), params);
  console.log('popup', params.get('security'), params.get('humans'));

  const securityTxt = document.querySelector('#securityTxt > textarea');
  const securityTab = document.querySelector('#securityTabLabel');


@@ 15,43 17,43 @@ window.addEventListener('DOMContentLoaded', () => {
  const clipboardHumans = document.querySelector('#humansTxt button');
  const msgTimeout = 3000;

  let hostJSON = localStorage.getItem(host);
  let hostData;

  i18nHydrate();

  if (hostJSON) {
    try {
      hostData = JSON.parse(hostJSON);
    } catch (e) {
      console.error(host, hostJSON, e);
      return;
    }
  }

  if (hostData.security) {
    securityTxt.value = hostData.security.text;
  if (params.get('security')) {
    fetch(params.get('security')).then((result) => {
      result.text().then((text) => {
        securityTxt.value = text;
        securityTab.title = params.get('security');
      });
    });
  } else {
    securityTab.style.display = 'none';
  }

  if (hostData.humans) {
    humansTxt.value = hostData.humans.text;
  if (params.get('humans')) {
    fetch(params.get('humans')).then((result) => {
      result.text().then((text) => {
        humansTxt.value = text;
        humansTab.title = params.get('humans');
        if (!params.get('security')) {
          securityInput.checked = false;
          humansInput.checked = true;
        }
      });
    });
  } else {
    humansTab.style.display = 'none';
  }

  if (hostData.humans && !hostData.security) {
    securityInput.checked = false;
    humansInput.checked = true;
  }
  i18nHydrate();

  clipboardSecurity.addEventListener('click', () => {
    securityTxt.select();
    document.execCommand('copy');
    clipboardSecurity.innerText = i18n('copied_security_to_clipboard');
    clipboardSecurity.disabled = true;
    setTimeout(() => {
      clipboardSecurity.innerText = i18n('copy_security_clipboard');
      clipboardSecurity.disabled = false;
    }, msgTimeout);
  });



@@ 59,8 61,10 @@ window.addEventListener('DOMContentLoaded', () => {
    humansTxt.select();
    document.execCommand('copy');
    clipboardHumans.innerText = i18n('copied_humans_to_clipboard');
    clipboardHumans.disabled = true;
    setTimeout(() => {
      clipboardHumans.innerText = i18n('copy_humans_clipboard');
      clipboardHumans.disabled = false;
    }, msgTimeout);
  });


M src/manifest.json => src/manifest.json +4 -8
@@ 9,14 9,10 @@
  "default_locale": "en",
  "incognito": "split",
  "icons": {
    "19": "img/19.png",
    "20": "img/20.png",
    "30": "img/30.png",
    "35": "img/35.png",
    "38": "img/38.png",
    "40": "img/40.png",
    "48": "img/48.png",
    "96": "img/96.png"
    "16": "img/info.16.png",
    "48": "img/info.48.png",
    "96": "img/info.96.png",
    "128": "img/info.128.png"
  },
  "permissions": [
    "http://*/.well-known/security.txt",

M src/options.html => src/options.html +0 -10
@@ 23,16 23,6 @@
        </select>
      </div>
      <div>
        <label for="host_cache_ttl" data-i18n></label>
        <select id="host_cache_ttl" class="browser-style" data-i18n>
          <option value="10M"></option>
          <option value="1H"></option>
          <option value="24H"></option>
          <option value="ALWAYS"></option>
          <option value="NEVER"></option>
        </select>
      </div>
      <div>
        <button type="button" id="reset_default" data-i18n class="browser-style"></button>
      </div>
    </form>

M src/popup.html => src/popup.html +1 -0
@@ 19,6 19,7 @@
        <textarea spellcheck="false"></textarea>
      </div>
    </div>
    <script src="js/browser-polyfill.js"></script>
    <script src="js/global.js"></script>
    <script src="js/i18n.js"></script>
    <script src="js/popup.js"></script>

M src/release.html => src/release.html +1 -0
@@ 19,6 19,7 @@
    <footer>
      <p>&copy; <span class="current-year"></span> <a href="https://www.harmless.systems">Harmless Systems</a></p>
    </footer>
    <script src="js/browser-polyfill.js"></script>
    <script src="js/global.js"></script>
    <script src="js/i18n.js"></script>
  </body>