├── test ├── test_helper.exs ├── fixtures │ ├── test_content_sri_no_scripts.html │ ├── test_content_sri_sameorigin1.html │ ├── test_content_sri_sameorigin3.html │ ├── test_content_sri_sameorigin2.html │ ├── test_content_sri_notimpl_external_http.html │ ├── test_content_sri_notimpl_external_https.html │ ├── test_content_sri_notimpl_external_noproto.html │ ├── test_parse_http_equiv_headers_referrer1.html │ ├── test_parse_http_equiv_headers_case_insensitivity.html │ ├── test_parse_http_equiv_headers_csp1.html │ ├── test_content_sri_impl_external_noproto.html │ ├── test_content_sri_impl_sameorigin.html │ ├── test_content_sri_impl_external_https1.html │ ├── test_content_sri_impl_external_https2.html │ ├── test_content_sri_impl_external_http.html │ ├── test_parse_http_equiv_headers_csp_multiple_http_equiv1.html │ ├── referrer_header.json │ ├── csp_referrer.json │ ├── header_csp.json │ ├── meta_csp.json │ ├── csp_and_referrer_header.json │ ├── csp_and_meta_referrer.json │ └── header_csp_and_meta_csp.json └── support │ ├── factory.ex │ ├── model_case.ex │ └── conn_case.ex ├── assets ├── static │ ├── favicon.ico │ ├── images │ │ ├── iis.png │ │ ├── phoenix.png │ │ ├── sort_asc.png │ │ ├── sort_both.png │ │ ├── sort_desc.png │ │ ├── ajax-loader.gif │ │ ├── mstile-70x70.png │ │ ├── dataskydd_eye2.png │ │ ├── favicon-160x160.png │ │ ├── favicon-16x16.png │ │ ├── favicon-192x192.png │ │ ├── favicon-32x32.png │ │ ├── favicon-96x96.png │ │ ├── internetfonden.png │ │ ├── mstile-144x144.png │ │ ├── mstile-150x150.png │ │ ├── mstile-310x150.png │ │ ├── mstile-310x310.png │ │ ├── apple-touch-icon.png │ │ ├── sort_asc_disabled.png │ │ ├── sort_desc_disabled.png │ │ ├── apple-touch-icon-57x57.png │ │ ├── apple-touch-icon-60x60.png │ │ ├── apple-touch-icon-72x72.png │ │ ├── apple-touch-icon-76x76.png │ │ ├── apple-touch-icon-114x114.png │ │ ├── apple-touch-icon-120x120.png │ │ ├── apple-touch-icon-144x144.png │ │ ├── apple-touch-icon-152x152.png │ │ ├── apple-touch-icon-180x180.png │ │ └── apple-touch-icon-precomposed.png │ ├── fonts │ │ ├── icomoon.ttf │ │ └── icomoon.woff │ ├── robots.txt │ └── js │ │ ├── webbkoll-30-app.js │ │ ├── webbkoll-20-a11y-toggle.min.js │ │ ├── html5shiv.min.js │ │ └── webbkoll-10-tablesort.min.js └── scss │ ├── base │ ├── _media.scss │ ├── _lists.scss │ ├── _layout.scss │ ├── _base.scss │ ├── _tables.scss │ ├── _variables.scss │ ├── _buttons.scss │ ├── _typography.scss │ └── _forms.scss │ ├── .sass-cache │ ├── 3ce5d73f8c8748aaab73244e13ce3309008dfaff │ │ ├── _shade.scssc │ │ ├── _tint.scssc │ │ ├── _contains.scssc │ │ ├── _is-light.scssc │ │ ├── _is-size.scssc │ │ ├── _px-to-em.scssc │ │ ├── _unpack.scssc │ │ ├── _is-length.scssc │ │ ├── _is-number.scssc │ │ ├── _px-to-rem.scssc │ │ ├── _assign-inputs.scssc │ │ ├── _modular-scale.scssc │ │ ├── _strip-units.scssc │ │ ├── _contains-falsy.scssc │ │ └── _transition-property-name.scssc │ ├── 7bc181db2811153f2eda76ec20c365d05dee6ca9 │ │ ├── _size.scssc │ │ ├── _buttons.scssc │ │ ├── _clearfix.scssc │ │ ├── _ellipsis.scssc │ │ ├── _margin.scssc │ │ ├── _padding.scssc │ │ ├── _position.scssc │ │ ├── _prefixer.scssc │ │ ├── _triangle.scssc │ │ ├── _hide-text.scssc │ │ ├── _word-wrap.scssc │ │ ├── _border-color.scssc │ │ ├── _border-radius.scssc │ │ ├── _border-style.scssc │ │ ├── _border-width.scssc │ │ ├── _font-stacks.scssc │ │ ├── _retina-image.scssc │ │ ├── _text-inputs.scssc │ │ └── _timing-functions.scssc │ ├── 72dda0c11013fc7994d6c543544dc280a238d0cf │ │ ├── _columns.scssc │ │ ├── _filter.scssc │ │ ├── _flex-box.scssc │ │ ├── _hyphens.scssc │ │ ├── _animation.scssc │ │ ├── _background.scssc │ │ ├── _font-face.scssc │ │ ├── _keyframes.scssc │ │ ├── _transform.scssc │ │ ├── _transition.scssc │ │ ├── _border-image.scssc │ │ ├── _perspective.scssc │ │ ├── _placeholder.scssc │ │ ├── _image-rendering.scssc │ │ ├── _linear-gradient.scssc │ │ ├── _radial-gradient.scssc │ │ ├── _background-image.scssc │ │ ├── _hidpi-media-query.scssc │ │ ├── _font-feature-settings.scssc │ │ ├── _backface-visibility.scssc │ │ ├── _appearance.scssc │ │ ├── _user-select.scssc │ │ └── _calc.scssc │ ├── de6a90186ec01c55797e67b1b16ce7162a29f933 │ │ ├── _bourbon.scssc │ │ └── _bourbon-deprecated-upcoming.scssc │ ├── b30e70bc19d73593335073523afe52a547588227 │ │ ├── _str-to-num.scssc │ │ ├── _convert-units.scssc │ │ ├── _directional-values.scssc │ │ ├── _radial-arg-parser.scssc │ │ ├── _render-gradients.scssc │ │ ├── _linear-angle-parser.scssc │ │ ├── _font-source-declaration.scssc │ │ ├── _linear-gradient-parser.scssc │ │ ├── _linear-positions-parser.scssc │ │ ├── _radial-gradient-parser.scssc │ │ ├── _radial-positions-parser.scssc │ │ ├── _gradient-positions-parser.scssc │ │ └── _linear-side-corner-parser.scssc │ ├── 74571de3e827f0001966c84f665e8974ed75748e │ │ ├── _asset-pipeline.scssc │ │ ├── _px-to-em.scssc │ │ └── _prefixer.scssc │ └── c5b9bd97b08c64c7fb937eb29bc46d18ccdc9322 │ │ └── style.scssc │ ├── neat │ ├── _neat-helpers.scss │ ├── grid │ │ ├── _box-sizing.scss │ │ ├── _reset-display.scss │ │ ├── _fill-parent.scss │ │ ├── _pad.scss │ │ ├── _display-context.scss │ │ ├── _direction-context.scss │ │ ├── _outer-container.scss │ │ ├── _private.scss │ │ ├── _visual-grid.scss │ │ ├── _row.scss │ │ └── _shift.scss │ ├── settings │ │ ├── _disable-warnings.scss │ │ ├── _visual-grid.scss │ │ └── _grid.scss │ ├── mixins │ │ └── _clearfix.scss │ ├── _neat.scss │ └── functions │ │ └── _new-breakpoint.scss │ ├── bourbon │ ├── bourbon │ │ ├── helpers │ │ │ ├── _buttons-list.scss │ │ │ ├── _text-inputs-list.scss │ │ │ └── _scales.scss │ │ ├── validators │ │ │ ├── _is-color.scss │ │ │ ├── _is-number.scss │ │ │ ├── _contains-falsy.scss │ │ │ ├── _is-length.scss │ │ │ ├── _is-size.scss │ │ │ └── _contains.scss │ │ ├── library │ │ │ ├── _strip-unit.scss │ │ │ ├── _clearfix.scss │ │ │ ├── _hide-text.scss │ │ │ ├── _overflow-wrap.scss │ │ │ ├── _border-width.scss │ │ │ ├── _border-style.scss │ │ │ ├── _tint.scss │ │ │ ├── _shade.scss │ │ │ ├── _border-color.scss │ │ │ ├── _prefixer.scss │ │ │ ├── _value-prefixer.scss │ │ │ ├── _ellipsis.scss │ │ │ ├── _padding.scss │ │ │ ├── _margin.scss │ │ │ ├── _size.scss │ │ │ ├── _position.scss │ │ │ ├── _timing-functions.scss │ │ │ ├── _hide-visually.scss │ │ │ ├── _font-face.scss │ │ │ ├── _border-radius.scss │ │ │ ├── _buttons.scss │ │ │ └── _triangle.scss │ │ └── utilities │ │ │ ├── _fetch-bourbon-setting.scss │ │ │ ├── _gamma.scss │ │ │ ├── _assign-inputs.scss │ │ │ ├── _lightness.scss │ │ │ ├── _contrast-ratio.scss │ │ │ ├── _unpack-shorthand.scss │ │ │ ├── _compact-shorthand.scss │ │ │ ├── _font-source-declaration.scss │ │ │ └── _directional-property.scss │ └── _bourbon.scss │ ├── _grid-settings.scss │ ├── _tablesort.scss │ ├── _compatibility.scss │ ├── _icons.scss │ └── _tooltip.scss ├── lib ├── webbkoll │ ├── scheduler.ex │ ├── sites │ │ ├── site.ex │ │ └── sites.ex │ ├── cronjobs.ex │ ├── application.ex │ ├── helpers.ex │ └── trackers.ex ├── webbkoll_web │ ├── views │ │ ├── page_view.ex │ │ ├── api │ │ │ └── site_view.ex │ │ ├── error_view.ex │ │ ├── layout_view.ex │ │ └── error_helpers.ex │ ├── templates │ │ ├── error │ │ │ └── error.html.heex │ │ ├── site │ │ │ ├── status.html.heex │ │ │ ├── _raw_headers.html.heex │ │ │ ├── results.html.heex │ │ │ ├── _what.html.heex │ │ │ ├── _cookie_table.html.heex │ │ │ ├── _hsts_host.html.heex │ │ │ ├── _request_table.html.heex │ │ │ ├── _localstorage.html.heex │ │ │ ├── _requests.html.heex │ │ │ └── _geolocation.html.heex │ │ └── page │ │ │ ├── donate.html.heex │ │ │ └── index.html.heex │ ├── plugs │ │ └── more_secure_headers.ex │ ├── gettext.ex │ ├── controllers │ │ ├── controller_helpers.ex │ │ ├── page_controller.ex │ │ └── api │ │ │ └── site_controller.ex │ ├── endpoint.ex │ └── router.ex └── webbkoll_web.ex ├── README.md ├── .formatter.exs ├── ansible ├── files │ └── webbkoll-backend.service ├── vars.yml ├── templates │ ├── webbkoll.service.j2 │ └── Caddyfile.j2 └── README ├── TRANSLATIONS.md ├── config ├── prod.exs ├── test.exs ├── dev.exs ├── runtime.exs └── config.exs ├── .gitignore ├── LICENSE └── mix.exs /test/test_helper.exs: -------------------------------------------------------------------------------- 1 | {:ok, _} = Application.ensure_all_started(:ex_machina) 2 | ExUnit.start() 3 | -------------------------------------------------------------------------------- /assets/static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/static/favicon.ico -------------------------------------------------------------------------------- /lib/webbkoll/scheduler.ex: -------------------------------------------------------------------------------- 1 | defmodule Webbkoll.Scheduler do 2 | use Quantum, otp_app: :webbkoll 3 | end 4 | -------------------------------------------------------------------------------- /assets/static/images/iis.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/static/images/iis.png -------------------------------------------------------------------------------- /lib/webbkoll_web/views/page_view.ex: -------------------------------------------------------------------------------- 1 | defmodule WebbkollWeb.PageView do 2 | use WebbkollWeb, :view 3 | end 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ⚠️ This repository has moved to Codeberg 2 | 3 | See https://codeberg.org/dataskydd.net/webbkoll 4 | -------------------------------------------------------------------------------- /assets/static/fonts/icomoon.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/static/fonts/icomoon.ttf -------------------------------------------------------------------------------- /assets/static/fonts/icomoon.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/static/fonts/icomoon.woff -------------------------------------------------------------------------------- /assets/static/images/phoenix.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/static/images/phoenix.png -------------------------------------------------------------------------------- /assets/static/images/sort_asc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/static/images/sort_asc.png -------------------------------------------------------------------------------- /assets/static/images/sort_both.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/static/images/sort_both.png -------------------------------------------------------------------------------- /assets/static/images/sort_desc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/static/images/sort_desc.png -------------------------------------------------------------------------------- /.formatter.exs: -------------------------------------------------------------------------------- 1 | [ 2 | import_deps: [:phoenix], 3 | inputs: ["*.{ex,exs}", "{config,lib,priv,test}/**/*.{ex,exs}"] 4 | ] 5 | -------------------------------------------------------------------------------- /assets/static/images/ajax-loader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/static/images/ajax-loader.gif -------------------------------------------------------------------------------- /assets/static/images/mstile-70x70.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/static/images/mstile-70x70.png -------------------------------------------------------------------------------- /assets/static/images/dataskydd_eye2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/static/images/dataskydd_eye2.png -------------------------------------------------------------------------------- /assets/static/images/favicon-160x160.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/static/images/favicon-160x160.png -------------------------------------------------------------------------------- /assets/static/images/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/static/images/favicon-16x16.png -------------------------------------------------------------------------------- /assets/static/images/favicon-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/static/images/favicon-192x192.png -------------------------------------------------------------------------------- /assets/static/images/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/static/images/favicon-32x32.png -------------------------------------------------------------------------------- /assets/static/images/favicon-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/static/images/favicon-96x96.png -------------------------------------------------------------------------------- /assets/static/images/internetfonden.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/static/images/internetfonden.png -------------------------------------------------------------------------------- /assets/static/images/mstile-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/static/images/mstile-144x144.png -------------------------------------------------------------------------------- /assets/static/images/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/static/images/mstile-150x150.png -------------------------------------------------------------------------------- /assets/static/images/mstile-310x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/static/images/mstile-310x150.png -------------------------------------------------------------------------------- /assets/static/images/mstile-310x310.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/static/images/mstile-310x310.png -------------------------------------------------------------------------------- /assets/static/images/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/static/images/apple-touch-icon.png -------------------------------------------------------------------------------- /assets/static/images/sort_asc_disabled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/static/images/sort_asc_disabled.png -------------------------------------------------------------------------------- /assets/static/images/sort_desc_disabled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/static/images/sort_desc_disabled.png -------------------------------------------------------------------------------- /assets/scss/base/_media.scss: -------------------------------------------------------------------------------- 1 | figure { 2 | margin: 0; 3 | } 4 | 5 | img, 6 | picture { 7 | margin: 0; 8 | max-width: 100%; 9 | } 10 | -------------------------------------------------------------------------------- /assets/static/images/apple-touch-icon-57x57.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/static/images/apple-touch-icon-57x57.png -------------------------------------------------------------------------------- /assets/static/images/apple-touch-icon-60x60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/static/images/apple-touch-icon-60x60.png -------------------------------------------------------------------------------- /assets/static/images/apple-touch-icon-72x72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/static/images/apple-touch-icon-72x72.png -------------------------------------------------------------------------------- /assets/static/images/apple-touch-icon-76x76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/static/images/apple-touch-icon-76x76.png -------------------------------------------------------------------------------- /assets/static/images/apple-touch-icon-114x114.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/static/images/apple-touch-icon-114x114.png -------------------------------------------------------------------------------- /assets/static/images/apple-touch-icon-120x120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/static/images/apple-touch-icon-120x120.png -------------------------------------------------------------------------------- /assets/static/images/apple-touch-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/static/images/apple-touch-icon-144x144.png -------------------------------------------------------------------------------- /assets/static/images/apple-touch-icon-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/static/images/apple-touch-icon-152x152.png -------------------------------------------------------------------------------- /assets/static/images/apple-touch-icon-180x180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/static/images/apple-touch-icon-180x180.png -------------------------------------------------------------------------------- /assets/static/images/apple-touch-icon-precomposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/static/images/apple-touch-icon-precomposed.png -------------------------------------------------------------------------------- /lib/webbkoll_web/templates/error/error.html.heex: -------------------------------------------------------------------------------- 1 |
2 |

<%= gettext "An error occurred" %>

3 | 4 |

<%= @error_message %>

5 |
-------------------------------------------------------------------------------- /lib/webbkoll_web/views/api/site_view.ex: -------------------------------------------------------------------------------- 1 | defmodule WebbkollWeb.API.SiteView do 2 | use WebbkollWeb, :view 3 | 4 | def render("show.json", assigns) do 5 | assigns.site 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /assets/scss/.sass-cache/3ce5d73f8c8748aaab73244e13ce3309008dfaff/_shade.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/scss/.sass-cache/3ce5d73f8c8748aaab73244e13ce3309008dfaff/_shade.scssc -------------------------------------------------------------------------------- /assets/scss/.sass-cache/3ce5d73f8c8748aaab73244e13ce3309008dfaff/_tint.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/scss/.sass-cache/3ce5d73f8c8748aaab73244e13ce3309008dfaff/_tint.scssc -------------------------------------------------------------------------------- /assets/scss/.sass-cache/7bc181db2811153f2eda76ec20c365d05dee6ca9/_size.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/scss/.sass-cache/7bc181db2811153f2eda76ec20c365d05dee6ca9/_size.scssc -------------------------------------------------------------------------------- /assets/scss/.sass-cache/3ce5d73f8c8748aaab73244e13ce3309008dfaff/_contains.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/scss/.sass-cache/3ce5d73f8c8748aaab73244e13ce3309008dfaff/_contains.scssc -------------------------------------------------------------------------------- /assets/scss/.sass-cache/3ce5d73f8c8748aaab73244e13ce3309008dfaff/_is-light.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/scss/.sass-cache/3ce5d73f8c8748aaab73244e13ce3309008dfaff/_is-light.scssc -------------------------------------------------------------------------------- /assets/scss/.sass-cache/3ce5d73f8c8748aaab73244e13ce3309008dfaff/_is-size.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/scss/.sass-cache/3ce5d73f8c8748aaab73244e13ce3309008dfaff/_is-size.scssc -------------------------------------------------------------------------------- /assets/scss/.sass-cache/3ce5d73f8c8748aaab73244e13ce3309008dfaff/_px-to-em.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/scss/.sass-cache/3ce5d73f8c8748aaab73244e13ce3309008dfaff/_px-to-em.scssc -------------------------------------------------------------------------------- /assets/scss/.sass-cache/3ce5d73f8c8748aaab73244e13ce3309008dfaff/_unpack.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/scss/.sass-cache/3ce5d73f8c8748aaab73244e13ce3309008dfaff/_unpack.scssc -------------------------------------------------------------------------------- /assets/scss/.sass-cache/72dda0c11013fc7994d6c543544dc280a238d0cf/_columns.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/scss/.sass-cache/72dda0c11013fc7994d6c543544dc280a238d0cf/_columns.scssc -------------------------------------------------------------------------------- /assets/scss/.sass-cache/72dda0c11013fc7994d6c543544dc280a238d0cf/_filter.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/scss/.sass-cache/72dda0c11013fc7994d6c543544dc280a238d0cf/_filter.scssc -------------------------------------------------------------------------------- /assets/scss/.sass-cache/72dda0c11013fc7994d6c543544dc280a238d0cf/_flex-box.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/scss/.sass-cache/72dda0c11013fc7994d6c543544dc280a238d0cf/_flex-box.scssc -------------------------------------------------------------------------------- /assets/scss/.sass-cache/72dda0c11013fc7994d6c543544dc280a238d0cf/_hyphens.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/scss/.sass-cache/72dda0c11013fc7994d6c543544dc280a238d0cf/_hyphens.scssc -------------------------------------------------------------------------------- /assets/scss/.sass-cache/7bc181db2811153f2eda76ec20c365d05dee6ca9/_buttons.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/scss/.sass-cache/7bc181db2811153f2eda76ec20c365d05dee6ca9/_buttons.scssc -------------------------------------------------------------------------------- /assets/scss/.sass-cache/7bc181db2811153f2eda76ec20c365d05dee6ca9/_clearfix.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/scss/.sass-cache/7bc181db2811153f2eda76ec20c365d05dee6ca9/_clearfix.scssc -------------------------------------------------------------------------------- /assets/scss/.sass-cache/7bc181db2811153f2eda76ec20c365d05dee6ca9/_ellipsis.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/scss/.sass-cache/7bc181db2811153f2eda76ec20c365d05dee6ca9/_ellipsis.scssc -------------------------------------------------------------------------------- /assets/scss/.sass-cache/7bc181db2811153f2eda76ec20c365d05dee6ca9/_margin.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/scss/.sass-cache/7bc181db2811153f2eda76ec20c365d05dee6ca9/_margin.scssc -------------------------------------------------------------------------------- /assets/scss/.sass-cache/7bc181db2811153f2eda76ec20c365d05dee6ca9/_padding.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/scss/.sass-cache/7bc181db2811153f2eda76ec20c365d05dee6ca9/_padding.scssc -------------------------------------------------------------------------------- /assets/scss/.sass-cache/7bc181db2811153f2eda76ec20c365d05dee6ca9/_position.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/scss/.sass-cache/7bc181db2811153f2eda76ec20c365d05dee6ca9/_position.scssc -------------------------------------------------------------------------------- /assets/scss/.sass-cache/7bc181db2811153f2eda76ec20c365d05dee6ca9/_prefixer.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/scss/.sass-cache/7bc181db2811153f2eda76ec20c365d05dee6ca9/_prefixer.scssc -------------------------------------------------------------------------------- /assets/scss/.sass-cache/7bc181db2811153f2eda76ec20c365d05dee6ca9/_triangle.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/scss/.sass-cache/7bc181db2811153f2eda76ec20c365d05dee6ca9/_triangle.scssc -------------------------------------------------------------------------------- /assets/scss/.sass-cache/de6a90186ec01c55797e67b1b16ce7162a29f933/_bourbon.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/scss/.sass-cache/de6a90186ec01c55797e67b1b16ce7162a29f933/_bourbon.scssc -------------------------------------------------------------------------------- /assets/scss/.sass-cache/3ce5d73f8c8748aaab73244e13ce3309008dfaff/_is-length.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/scss/.sass-cache/3ce5d73f8c8748aaab73244e13ce3309008dfaff/_is-length.scssc -------------------------------------------------------------------------------- /assets/scss/.sass-cache/3ce5d73f8c8748aaab73244e13ce3309008dfaff/_is-number.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/scss/.sass-cache/3ce5d73f8c8748aaab73244e13ce3309008dfaff/_is-number.scssc -------------------------------------------------------------------------------- /assets/scss/.sass-cache/3ce5d73f8c8748aaab73244e13ce3309008dfaff/_px-to-rem.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/scss/.sass-cache/3ce5d73f8c8748aaab73244e13ce3309008dfaff/_px-to-rem.scssc -------------------------------------------------------------------------------- /assets/scss/.sass-cache/72dda0c11013fc7994d6c543544dc280a238d0cf/_animation.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/scss/.sass-cache/72dda0c11013fc7994d6c543544dc280a238d0cf/_animation.scssc -------------------------------------------------------------------------------- /assets/scss/.sass-cache/72dda0c11013fc7994d6c543544dc280a238d0cf/_background.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/scss/.sass-cache/72dda0c11013fc7994d6c543544dc280a238d0cf/_background.scssc -------------------------------------------------------------------------------- /assets/scss/.sass-cache/72dda0c11013fc7994d6c543544dc280a238d0cf/_font-face.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/scss/.sass-cache/72dda0c11013fc7994d6c543544dc280a238d0cf/_font-face.scssc -------------------------------------------------------------------------------- /assets/scss/.sass-cache/72dda0c11013fc7994d6c543544dc280a238d0cf/_keyframes.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/scss/.sass-cache/72dda0c11013fc7994d6c543544dc280a238d0cf/_keyframes.scssc -------------------------------------------------------------------------------- /assets/scss/.sass-cache/72dda0c11013fc7994d6c543544dc280a238d0cf/_transform.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/scss/.sass-cache/72dda0c11013fc7994d6c543544dc280a238d0cf/_transform.scssc -------------------------------------------------------------------------------- /assets/scss/.sass-cache/72dda0c11013fc7994d6c543544dc280a238d0cf/_transition.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/scss/.sass-cache/72dda0c11013fc7994d6c543544dc280a238d0cf/_transition.scssc -------------------------------------------------------------------------------- /assets/scss/.sass-cache/7bc181db2811153f2eda76ec20c365d05dee6ca9/_hide-text.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/scss/.sass-cache/7bc181db2811153f2eda76ec20c365d05dee6ca9/_hide-text.scssc -------------------------------------------------------------------------------- /assets/scss/.sass-cache/7bc181db2811153f2eda76ec20c365d05dee6ca9/_word-wrap.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/scss/.sass-cache/7bc181db2811153f2eda76ec20c365d05dee6ca9/_word-wrap.scssc -------------------------------------------------------------------------------- /assets/scss/.sass-cache/b30e70bc19d73593335073523afe52a547588227/_str-to-num.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/scss/.sass-cache/b30e70bc19d73593335073523afe52a547588227/_str-to-num.scssc -------------------------------------------------------------------------------- /assets/scss/.sass-cache/3ce5d73f8c8748aaab73244e13ce3309008dfaff/_assign-inputs.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/scss/.sass-cache/3ce5d73f8c8748aaab73244e13ce3309008dfaff/_assign-inputs.scssc -------------------------------------------------------------------------------- /assets/scss/.sass-cache/3ce5d73f8c8748aaab73244e13ce3309008dfaff/_modular-scale.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/scss/.sass-cache/3ce5d73f8c8748aaab73244e13ce3309008dfaff/_modular-scale.scssc -------------------------------------------------------------------------------- /assets/scss/.sass-cache/3ce5d73f8c8748aaab73244e13ce3309008dfaff/_strip-units.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/scss/.sass-cache/3ce5d73f8c8748aaab73244e13ce3309008dfaff/_strip-units.scssc -------------------------------------------------------------------------------- /assets/scss/.sass-cache/72dda0c11013fc7994d6c543544dc280a238d0cf/_border-image.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/scss/.sass-cache/72dda0c11013fc7994d6c543544dc280a238d0cf/_border-image.scssc -------------------------------------------------------------------------------- /assets/scss/.sass-cache/72dda0c11013fc7994d6c543544dc280a238d0cf/_perspective.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/scss/.sass-cache/72dda0c11013fc7994d6c543544dc280a238d0cf/_perspective.scssc -------------------------------------------------------------------------------- /assets/scss/.sass-cache/72dda0c11013fc7994d6c543544dc280a238d0cf/_placeholder.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/scss/.sass-cache/72dda0c11013fc7994d6c543544dc280a238d0cf/_placeholder.scssc -------------------------------------------------------------------------------- /assets/scss/.sass-cache/7bc181db2811153f2eda76ec20c365d05dee6ca9/_border-color.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/scss/.sass-cache/7bc181db2811153f2eda76ec20c365d05dee6ca9/_border-color.scssc -------------------------------------------------------------------------------- /assets/scss/.sass-cache/7bc181db2811153f2eda76ec20c365d05dee6ca9/_border-radius.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/scss/.sass-cache/7bc181db2811153f2eda76ec20c365d05dee6ca9/_border-radius.scssc -------------------------------------------------------------------------------- /assets/scss/.sass-cache/7bc181db2811153f2eda76ec20c365d05dee6ca9/_border-style.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/scss/.sass-cache/7bc181db2811153f2eda76ec20c365d05dee6ca9/_border-style.scssc -------------------------------------------------------------------------------- /assets/scss/.sass-cache/7bc181db2811153f2eda76ec20c365d05dee6ca9/_border-width.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/scss/.sass-cache/7bc181db2811153f2eda76ec20c365d05dee6ca9/_border-width.scssc -------------------------------------------------------------------------------- /assets/scss/.sass-cache/7bc181db2811153f2eda76ec20c365d05dee6ca9/_font-stacks.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/scss/.sass-cache/7bc181db2811153f2eda76ec20c365d05dee6ca9/_font-stacks.scssc -------------------------------------------------------------------------------- /assets/scss/.sass-cache/7bc181db2811153f2eda76ec20c365d05dee6ca9/_retina-image.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/scss/.sass-cache/7bc181db2811153f2eda76ec20c365d05dee6ca9/_retina-image.scssc -------------------------------------------------------------------------------- /assets/scss/.sass-cache/7bc181db2811153f2eda76ec20c365d05dee6ca9/_text-inputs.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/scss/.sass-cache/7bc181db2811153f2eda76ec20c365d05dee6ca9/_text-inputs.scssc -------------------------------------------------------------------------------- /assets/scss/.sass-cache/b30e70bc19d73593335073523afe52a547588227/_convert-units.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/scss/.sass-cache/b30e70bc19d73593335073523afe52a547588227/_convert-units.scssc -------------------------------------------------------------------------------- /assets/scss/.sass-cache/3ce5d73f8c8748aaab73244e13ce3309008dfaff/_contains-falsy.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/scss/.sass-cache/3ce5d73f8c8748aaab73244e13ce3309008dfaff/_contains-falsy.scssc -------------------------------------------------------------------------------- /assets/scss/.sass-cache/72dda0c11013fc7994d6c543544dc280a238d0cf/_image-rendering.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/scss/.sass-cache/72dda0c11013fc7994d6c543544dc280a238d0cf/_image-rendering.scssc -------------------------------------------------------------------------------- /assets/scss/.sass-cache/72dda0c11013fc7994d6c543544dc280a238d0cf/_linear-gradient.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/scss/.sass-cache/72dda0c11013fc7994d6c543544dc280a238d0cf/_linear-gradient.scssc -------------------------------------------------------------------------------- /assets/scss/.sass-cache/72dda0c11013fc7994d6c543544dc280a238d0cf/_radial-gradient.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/scss/.sass-cache/72dda0c11013fc7994d6c543544dc280a238d0cf/_radial-gradient.scssc -------------------------------------------------------------------------------- /assets/scss/.sass-cache/74571de3e827f0001966c84f665e8974ed75748e/_asset-pipeline.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/scss/.sass-cache/74571de3e827f0001966c84f665e8974ed75748e/_asset-pipeline.scssc -------------------------------------------------------------------------------- /assets/scss/.sass-cache/72dda0c11013fc7994d6c543544dc280a238d0cf/_background-image.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/scss/.sass-cache/72dda0c11013fc7994d6c543544dc280a238d0cf/_background-image.scssc -------------------------------------------------------------------------------- /assets/scss/.sass-cache/72dda0c11013fc7994d6c543544dc280a238d0cf/_hidpi-media-query.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/scss/.sass-cache/72dda0c11013fc7994d6c543544dc280a238d0cf/_hidpi-media-query.scssc -------------------------------------------------------------------------------- /assets/scss/.sass-cache/7bc181db2811153f2eda76ec20c365d05dee6ca9/_timing-functions.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/scss/.sass-cache/7bc181db2811153f2eda76ec20c365d05dee6ca9/_timing-functions.scssc -------------------------------------------------------------------------------- /assets/scss/.sass-cache/b30e70bc19d73593335073523afe52a547588227/_directional-values.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/scss/.sass-cache/b30e70bc19d73593335073523afe52a547588227/_directional-values.scssc -------------------------------------------------------------------------------- /assets/scss/.sass-cache/b30e70bc19d73593335073523afe52a547588227/_radial-arg-parser.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/scss/.sass-cache/b30e70bc19d73593335073523afe52a547588227/_radial-arg-parser.scssc -------------------------------------------------------------------------------- /assets/scss/.sass-cache/b30e70bc19d73593335073523afe52a547588227/_render-gradients.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/scss/.sass-cache/b30e70bc19d73593335073523afe52a547588227/_render-gradients.scssc -------------------------------------------------------------------------------- /assets/scss/.sass-cache/b30e70bc19d73593335073523afe52a547588227/_linear-angle-parser.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/scss/.sass-cache/b30e70bc19d73593335073523afe52a547588227/_linear-angle-parser.scssc -------------------------------------------------------------------------------- /assets/scss/.sass-cache/72dda0c11013fc7994d6c543544dc280a238d0cf/_font-feature-settings.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/scss/.sass-cache/72dda0c11013fc7994d6c543544dc280a238d0cf/_font-feature-settings.scssc -------------------------------------------------------------------------------- /assets/scss/.sass-cache/b30e70bc19d73593335073523afe52a547588227/_font-source-declaration.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/scss/.sass-cache/b30e70bc19d73593335073523afe52a547588227/_font-source-declaration.scssc -------------------------------------------------------------------------------- /assets/scss/.sass-cache/b30e70bc19d73593335073523afe52a547588227/_linear-gradient-parser.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/scss/.sass-cache/b30e70bc19d73593335073523afe52a547588227/_linear-gradient-parser.scssc -------------------------------------------------------------------------------- /assets/scss/.sass-cache/b30e70bc19d73593335073523afe52a547588227/_linear-positions-parser.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/scss/.sass-cache/b30e70bc19d73593335073523afe52a547588227/_linear-positions-parser.scssc -------------------------------------------------------------------------------- /assets/scss/.sass-cache/b30e70bc19d73593335073523afe52a547588227/_radial-gradient-parser.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/scss/.sass-cache/b30e70bc19d73593335073523afe52a547588227/_radial-gradient-parser.scssc -------------------------------------------------------------------------------- /assets/scss/.sass-cache/b30e70bc19d73593335073523afe52a547588227/_radial-positions-parser.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/scss/.sass-cache/b30e70bc19d73593335073523afe52a547588227/_radial-positions-parser.scssc -------------------------------------------------------------------------------- /assets/scss/.sass-cache/3ce5d73f8c8748aaab73244e13ce3309008dfaff/_transition-property-name.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/scss/.sass-cache/3ce5d73f8c8748aaab73244e13ce3309008dfaff/_transition-property-name.scssc -------------------------------------------------------------------------------- /assets/scss/.sass-cache/b30e70bc19d73593335073523afe52a547588227/_gradient-positions-parser.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/scss/.sass-cache/b30e70bc19d73593335073523afe52a547588227/_gradient-positions-parser.scssc -------------------------------------------------------------------------------- /assets/scss/.sass-cache/b30e70bc19d73593335073523afe52a547588227/_linear-side-corner-parser.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/scss/.sass-cache/b30e70bc19d73593335073523afe52a547588227/_linear-side-corner-parser.scssc -------------------------------------------------------------------------------- /assets/scss/.sass-cache/de6a90186ec01c55797e67b1b16ce7162a29f933/_bourbon-deprecated-upcoming.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andersju/webbkoll/HEAD/assets/scss/.sass-cache/de6a90186ec01c55797e67b1b16ce7162a29f933/_bourbon-deprecated-upcoming.scssc -------------------------------------------------------------------------------- /test/fixtures/test_content_sri_no_scripts.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /assets/scss/base/_lists.scss: -------------------------------------------------------------------------------- 1 | ul, 2 | ol { 3 | list-style-type: none; 4 | margin: 0; 5 | padding: 0; 6 | } 7 | 8 | dl { 9 | margin: 0; 10 | } 11 | 12 | dt { 13 | font-weight: 600; 14 | margin: 0; 15 | } 16 | 17 | dd { 18 | margin: 0; 19 | } 20 | -------------------------------------------------------------------------------- /test/fixtures/test_content_sri_sameorigin1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /test/fixtures/test_content_sri_sameorigin3.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ansible/files/webbkoll-backend.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Webbkoll-backend 3 | 4 | [Service] 5 | Type=simple 6 | ExecStart=npm start 7 | WorkingDirectory=/home/webbkoll/webbkoll-backend 8 | User=webbkoll 9 | Group=webbkoll 10 | Restart=always 11 | 12 | [Install] 13 | WantedBy=multi-user.target -------------------------------------------------------------------------------- /test/fixtures/test_content_sri_sameorigin2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /assets/scss/base/_layout.scss: -------------------------------------------------------------------------------- 1 | html { 2 | background-color: $viewport-background-color; 3 | box-sizing: border-box; 4 | } 5 | 6 | *, 7 | *::before, 8 | *::after { 9 | box-sizing: inherit; 10 | } 11 | 12 | html, 13 | body { 14 | height: 100%; 15 | } 16 | 17 | body { 18 | margin: 0; 19 | } 20 | -------------------------------------------------------------------------------- /assets/scss/neat/_neat-helpers.scss: -------------------------------------------------------------------------------- 1 | // Mixins 2 | @import "mixins/clearfix"; 3 | 4 | // Functions 5 | @import "functions/private"; 6 | @import "functions/new-breakpoint"; 7 | 8 | // Settings 9 | @import "settings/grid"; 10 | @import "settings/visual-grid"; 11 | @import "settings/disable-warnings"; 12 | -------------------------------------------------------------------------------- /assets/scss/neat/grid/_box-sizing.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | @if $border-box-sizing == true { 4 | html { // http://bit.ly/1qk2tVR 5 | box-sizing: border-box; 6 | } 7 | 8 | * { 9 | &, 10 | &::after, 11 | &::before { 12 | box-sizing: inherit; 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /ansible/vars.yml: -------------------------------------------------------------------------------- 1 | webbkoll_host: "{{ lookup('env','WEBBKOLL_HOST') or 'webbkoll.dataskydd.net' }}" 2 | # Set WEBBKOLL_CADDY_PREFIX to 'http://' to disable TLS in Caddy 3 | caddy_prefix: "{{ lookup('env','WEBBKOLL_CADDY_PREFIX') or '' }}" 4 | created_username: "{{ lookup('env','WEBBKOLL_ANSIBLE_USERNAME') or 'ansible' }}" -------------------------------------------------------------------------------- /assets/scss/bourbon/bourbon/helpers/_buttons-list.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// A list of all HTML button elements. 4 | /// 5 | /// @type list 6 | /// 7 | /// @access private 8 | 9 | $_buttons-list: ( 10 | "button", 11 | "[type='button']", 12 | "[type='reset']", 13 | "[type='submit']", 14 | ); 15 | -------------------------------------------------------------------------------- /TRANSLATIONS.md: -------------------------------------------------------------------------------- 1 | ## Translating Webbkoll 2 | 3 | You are very welcome to help us translate Webbkoll to languages other than English/Swedish. 4 | 5 | For this purpose we use the translation tool Weblate; see https://hosted.weblate.org/projects/webbkoll/, 6 | where you can create an account and start translating. The base language is English. 7 | -------------------------------------------------------------------------------- /lib/webbkoll/sites/site.ex: -------------------------------------------------------------------------------- 1 | defmodule Webbkoll.Sites.Site do 2 | @derive Jason.Encoder 3 | 4 | defstruct [ 5 | :id, 6 | :input_url, 7 | :try_count, 8 | :status, 9 | :status_message, 10 | :data, 11 | :inserted_at, 12 | :updated_at, 13 | :headers, 14 | :response_status, 15 | ] 16 | end 17 | -------------------------------------------------------------------------------- /test/fixtures/test_content_sri_notimpl_external_http.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /test/fixtures/test_content_sri_notimpl_external_https.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /test/fixtures/test_content_sri_notimpl_external_noproto.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /assets/scss/base/_base.scss: -------------------------------------------------------------------------------- 1 | // Bitters 1.8.0 2 | // http://bitters.bourbon.io 3 | // Copyright 2013-2017 thoughtbot, inc. 4 | // MIT License 5 | 6 | @import "variables"; 7 | 8 | @import "buttons"; 9 | @import "forms"; 10 | @import "layout"; 11 | @import "lists"; 12 | @import "media"; 13 | @import "tables"; 14 | @import "typography"; 15 | -------------------------------------------------------------------------------- /test/support/factory.ex: -------------------------------------------------------------------------------- 1 | defmodule Webbkoll.Factory do 2 | use ExMachina 3 | 4 | def site_factory do 5 | %Webbkoll.Sites.Site{ 6 | input_url: "example.com", 7 | status: "done", 8 | inserted_at: System.system_time(:microsecond), 9 | updated_at: System.system_time(:microsecond) 10 | } 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /assets/scss/bourbon/bourbon/validators/_is-color.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Checks for a valid CSS color. 4 | /// 5 | /// @argument {string} $color 6 | /// 7 | /// @return {boolean} 8 | /// 9 | /// @access private 10 | 11 | @function _is-color($color) { 12 | @return (type-of($color) == color) or ($color == "currentColor"); 13 | } 14 | -------------------------------------------------------------------------------- /assets/static/robots.txt: -------------------------------------------------------------------------------- 1 | # See http://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file 2 | # 3 | # To ban all spiders from the entire site uncomment the next two lines: 4 | # User-agent: * 5 | # Disallow: / 6 | 7 | User-agent: * 8 | Disallow: /*/check 9 | Disallow: /*/status 10 | Disallow: /*/results 11 | 12 | -------------------------------------------------------------------------------- /assets/scss/neat/settings/_disable-warnings.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Disable all deprecation warnings. Defaults to `false`. Set with a `!global` flag. 4 | /// 5 | /// @type Bool 6 | 7 | $disable-warnings: false !default; 8 | 9 | @mixin -neat-warn($message) { 10 | @if $disable-warnings == false { 11 | @warn "#{$message}"; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /lib/webbkoll_web/templates/site/status.html.heex: -------------------------------------------------------------------------------- 1 |
2 |

<%= gettext "Checking..." %>

3 | 4 |

5 | 6 | 10 |
-------------------------------------------------------------------------------- /test/fixtures/test_parse_http_equiv_headers_referrer1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Title 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /test/fixtures/test_parse_http_equiv_headers_case_insensitivity.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Title 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /test/fixtures/test_parse_http_equiv_headers_csp1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Title 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /assets/scss/bourbon/bourbon/validators/_is-number.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Checks for a valid number. 4 | /// 5 | /// @argument {number} $value 6 | /// 7 | /// @require {function} _contains 8 | /// 9 | /// @return {boolean} 10 | /// 11 | /// @access private 12 | 13 | @function _is-number($value) { 14 | @return _contains("0" "1" "2" "3" "4" "5" "6" "7" "8" "9" 0 1 2 3 4 5 6 7 8 9, $value); 15 | } 16 | -------------------------------------------------------------------------------- /assets/scss/bourbon/bourbon/library/_strip-unit.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Strips the unit from a number. 4 | /// 5 | /// @argument {number} $value 6 | /// 7 | /// @return {number (unitless)} 8 | /// 9 | /// @example scss 10 | /// $dimension: strip-unit(10em); 11 | /// 12 | /// // Output 13 | /// $dimension: 10; 14 | 15 | @function strip-unit($value) { 16 | @return ($value / ($value * 0 + 1)); 17 | } 18 | -------------------------------------------------------------------------------- /test/fixtures/test_content_sri_impl_external_noproto.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /test/fixtures/test_content_sri_impl_sameorigin.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ansible/templates/webbkoll.service.j2: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Webbkoll 3 | 4 | [Service] 5 | Type=simple 6 | ExecStart=mix phx.server 7 | WorkingDirectory=/home/webbkoll/webbkoll 8 | Environment=MIX_ENV=prod 9 | Environment=PORT=4000 10 | Environment=PHX_HOST={{ webbkoll_host }} 11 | Environment=SECRET_KEY_BASE={{ secret_key_base }} 12 | User=webbkoll 13 | Group=webbkoll 14 | Restart=always 15 | 16 | [Install] 17 | WantedBy=multi-user.target -------------------------------------------------------------------------------- /ansible/README: -------------------------------------------------------------------------------- 1 | Assumes Ubuntu 22.04. 2 | 3 | If local server, set some vars before prepare and deploy: 4 | 5 | WEBBKOLL_HOST=webbkoll.local 6 | WEBBKOLL_CADDY_PREFIX="http://" 7 | 8 | First: 9 | 10 | ansible-playbook -i webbkoll.local, -u root prepare.yml 11 | 12 | -u ansible thereafter: 13 | 14 | ansible-playbook -i webbkoll.local, -u ansible prepare.yml 15 | 16 | Deploy: 17 | 18 | ansible-playbook -i webbkoll.local, -u ansible deploy.yml 19 | -------------------------------------------------------------------------------- /assets/scss/_grid-settings.scss: -------------------------------------------------------------------------------- 1 | @import "bourbon/bourbon"; // or "bourbon" when in Rails 2 | @import "neat/neat-helpers"; // or "neat-helpers" when in Rails 3 | 4 | // Change the grid settings 5 | //$column: 90px; 6 | //$gutter: 30px; 7 | //$grid-columns: 10; 8 | //$max-width: 1200px; 9 | 10 | // Define your breakpoints 11 | $large: new-breakpoint(max-width 1250px 8); 12 | $tablet: new-breakpoint(max-width 768px 8); 13 | $mobile: new-breakpoint(max-width 480px 4); -------------------------------------------------------------------------------- /assets/scss/bourbon/bourbon/validators/_contains-falsy.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Checks if a list does not contain any values. 4 | /// 5 | /// @argument {list} $list 6 | /// The list to check against. 7 | /// 8 | /// @return {boolean} 9 | /// 10 | /// @access private 11 | 12 | @function _contains-falsy($list) { 13 | @each $item in $list { 14 | @if not $item { 15 | @return true; 16 | } 17 | } 18 | 19 | @return false; 20 | } 21 | -------------------------------------------------------------------------------- /lib/webbkoll_web/plugs/more_secure_headers.ex: -------------------------------------------------------------------------------- 1 | defmodule WebbkollWeb.Plugs.MoreSecureHeaders do 2 | import Plug.Conn 3 | 4 | def init(default), do: default 5 | 6 | def call(conn, _default) do 7 | conn 8 | |> put_resp_header( 9 | "Content-Security-Policy", 10 | "default-src 'self'; frame-ancestors 'none'; base-uri 'none'; form-action 'self'" 11 | ) 12 | |> put_resp_header("Referrer-Policy", "no-referrer") 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /assets/scss/bourbon/bourbon/validators/_is-length.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Checks for a valid CSS length. 4 | /// 5 | /// @argument {string} $value 6 | /// 7 | /// @return {boolean} 8 | /// 9 | /// @access private 10 | 11 | @function _is-length($value) { 12 | @return type-of($value) != "null" and (str-slice($value + "", 1, 4) == "calc" 13 | or index(auto inherit initial 0, $value) 14 | or (type-of($value) == "number" and not(unitless($value)))); 15 | } 16 | -------------------------------------------------------------------------------- /assets/scss/bourbon/bourbon/validators/_is-size.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Checks for a valid CSS size. 4 | /// 5 | /// @argument {string} $value 6 | /// 7 | /// @return {boolean} 8 | /// 9 | /// @require {function} _contains 10 | /// 11 | /// @require {function} _is-length 12 | /// 13 | /// @access private 14 | 15 | @function _is-size($value) { 16 | @return _is-length($value) 17 | or _contains("fill" "fit-content" "min-content" "max-content", $value); 18 | } 19 | -------------------------------------------------------------------------------- /assets/scss/bourbon/bourbon/utilities/_fetch-bourbon-setting.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Return a Bourbon setting. 4 | /// 5 | /// @argument {string} $setting 6 | /// 7 | /// @return {boolean | color | list | number | string} 8 | /// 9 | /// @example scss 10 | /// _fetch-bourbon-setting(rails-asset-pipeline) 11 | /// 12 | /// @access private 13 | 14 | @function _fetch-bourbon-setting($setting) { 15 | @return map-get(map-merge($_bourbon-defaults, $bourbon), $setting); 16 | } 17 | -------------------------------------------------------------------------------- /test/fixtures/test_content_sri_impl_external_https1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /assets/scss/neat/grid/_reset-display.scss: -------------------------------------------------------------------------------- 1 | /// Resets the active display property to `block`. Particularly useful when changing the display property in a single row. 2 | /// 3 | /// @example scss - Usage 4 | /// .element { 5 | /// @include row(table); 6 | /// // Context changed to table display 7 | /// } 8 | /// 9 | /// @include reset-display; 10 | /// // Context is reset to block display 11 | 12 | @mixin reset-display { 13 | $container-display-table: false !global; 14 | } 15 | -------------------------------------------------------------------------------- /test/fixtures/test_content_sri_impl_external_https2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /assets/scss/neat/grid/_fill-parent.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Forces the element to fill its parent container. 4 | /// 5 | /// @example scss - Usage 6 | /// .element { 7 | /// @include fill-parent; 8 | /// } 9 | /// 10 | /// @example css - CSS Output 11 | /// .element { 12 | /// width: 100%; 13 | /// box-sizing: border-box; 14 | /// } 15 | 16 | @mixin fill-parent() { 17 | width: 100%; 18 | 19 | @if $border-box-sizing == false { 20 | box-sizing: border-box; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /assets/scss/base/_tables.scss: -------------------------------------------------------------------------------- 1 | table { 2 | border-collapse: collapse; 3 | margin: $base-spacing 0; 4 | table-layout: fixed; 5 | text-align: left; 6 | width: 100%; 7 | } 8 | 9 | thead { 10 | line-height: $heading-line-height; 11 | vertical-align: bottom; 12 | } 13 | 14 | tbody { 15 | vertical-align: top; 16 | } 17 | 18 | tr { 19 | border-bottom: $base-border; 20 | } 21 | 22 | th { 23 | font-weight: 600; 24 | } 25 | 26 | th, 27 | td { 28 | padding: $small-spacing $small-spacing $small-spacing 0; 29 | } 30 | -------------------------------------------------------------------------------- /assets/scss/neat/mixins/_clearfix.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Provides an easy way to include a clearfix for containing floats. 4 | /// 5 | /// @link http://goo.gl/yP5hiZ 6 | /// 7 | /// @example scss 8 | /// .element { 9 | /// @include clearfix; 10 | /// } 11 | /// 12 | /// @example css 13 | /// .element::after { 14 | /// clear: both; 15 | /// content: ""; 16 | /// display: block; 17 | /// } 18 | 19 | @mixin clearfix { 20 | &::after { 21 | clear: both; 22 | content: ""; 23 | display: block; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /assets/scss/bourbon/bourbon/library/_clearfix.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Provides an easy way to include a clearfix for containing floats. 4 | /// 5 | /// @link https://goo.gl/yP5hiZ 6 | /// 7 | /// @example scss 8 | /// .element { 9 | /// @include clearfix; 10 | /// } 11 | /// 12 | /// // CSS Output 13 | /// .element::after { 14 | /// clear: both; 15 | /// content: ""; 16 | /// display: block; 17 | /// } 18 | 19 | @mixin clearfix { 20 | &::after { 21 | clear: both; 22 | content: ""; 23 | display: block; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /assets/scss/bourbon/bourbon/validators/_contains.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Checks if a list contains a value(s). 4 | /// 5 | /// @argument {list} $list 6 | /// The list to check against. 7 | /// 8 | /// @argument {list} $values 9 | /// A single value or list of values to check for. 10 | /// 11 | /// @return {boolean} 12 | /// 13 | /// @access private 14 | 15 | @function _contains( 16 | $list, 17 | $values... 18 | ) { 19 | @each $value in $values { 20 | @if type-of(index($list, $value)) != "number" { 21 | @return false; 22 | } 23 | } 24 | 25 | @return true; 26 | } 27 | -------------------------------------------------------------------------------- /assets/scss/bourbon/bourbon/helpers/_text-inputs-list.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// A list of all _text-based_ HTML inputs. 4 | /// 5 | /// @type list 6 | /// 7 | /// @access private 8 | 9 | $_text-inputs-list: ( 10 | "[type='color']", 11 | "[type='date']", 12 | "[type='datetime']", 13 | "[type='datetime-local']", 14 | "[type='email']", 15 | "[type='month']", 16 | "[type='number']", 17 | "[type='password']", 18 | "[type='search']", 19 | "[type='tel']", 20 | "[type='text']", 21 | "[type='time']", 22 | "[type='url']", 23 | "[type='week']", 24 | "input:not([type])", 25 | "textarea", 26 | ); 27 | -------------------------------------------------------------------------------- /assets/scss/bourbon/bourbon/library/_hide-text.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Hides the text in an element, commonly used to show an image instead. Some 4 | /// elements will need block-level styles applied. 5 | /// 6 | /// @link https://goo.gl/EvLRIu 7 | /// 8 | /// @example scss 9 | /// .element { 10 | /// @include hide-text; 11 | /// } 12 | /// 13 | /// // CSS Output 14 | /// .element { 15 | /// overflow: hidden; 16 | /// text-indent: 101%; 17 | /// white-space: nowrap; 18 | /// } 19 | 20 | @mixin hide-text { 21 | overflow: hidden; 22 | text-indent: 101%; 23 | white-space: nowrap; 24 | } 25 | -------------------------------------------------------------------------------- /lib/webbkoll_web/views/error_view.ex: -------------------------------------------------------------------------------- 1 | defmodule WebbkollWeb.ErrorView do 2 | use WebbkollWeb, :view 3 | 4 | def render(<> <> ".json", assigns) do 5 | %{ 6 | errors: %{ 7 | detail: assigns.error_message 8 | }, 9 | status: status 10 | } 11 | end 12 | 13 | def template_not_found(_template, %{error_message: error_message}) do 14 | render("error.html", error_message: error_message) 15 | end 16 | 17 | def template_not_found(template, _assigns) do 18 | render("error.html", error_message: Phoenix.Controller.status_message_from_template(template)) 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /config/prod.exs: -------------------------------------------------------------------------------- 1 | import Config 2 | 3 | # For production, don't forget to configure the url host 4 | # to something meaningful, Phoenix uses this information 5 | # when generating URLs. 6 | # 7 | # Note we also include the path to a cache manifest 8 | # containing the digested version of static files. This 9 | # manifest is generated by the `mix phx.digest` task, 10 | # which you should run after static files are built and 11 | # before starting your production server. 12 | config :webbkoll, WebbkollWeb.Endpoint, cache_static_manifest: "priv/static/cache_manifest.json" 13 | 14 | # Do not print debug messages in production 15 | config :logger, level: :info 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # App artifacts 2 | /_build 3 | /db 4 | /deps 5 | /*.ez 6 | 7 | # Generate on crash by the VM 8 | erl_crash.dump 9 | 10 | # Static artifacts 11 | /assets/node_modules 12 | /misc/backend/node_modules 13 | /priv/static/ 14 | 15 | # The config/prod.secret.exs file by default contains sensitive 16 | # data and you should not commit it into version control. 17 | # 18 | # Alternatively, you may comment the line below and commit the 19 | # secrets file as long as you replace its contents by environment 20 | # variables. 21 | /config/*.secret.exs 22 | *.swp 23 | *.log 24 | 25 | /rel/webbkoll 26 | /priv/*.mmdb 27 | /priv/*.mmdb.gz 28 | /priv/GeoLite2* 29 | -------------------------------------------------------------------------------- /assets/scss/neat/_neat.scss: -------------------------------------------------------------------------------- 1 | // Neat 1.9.1 2 | // http://neat.bourbon.io 3 | // Copyright 2012-2015 thoughtbot, inc. 4 | // MIT License 5 | 6 | // Helpers 7 | @import "neat-helpers"; 8 | 9 | // Grid 10 | @import "grid/private"; 11 | @import "grid/box-sizing"; 12 | @import "grid/omega"; 13 | @import "grid/outer-container"; 14 | @import "grid/span-columns"; 15 | @import "grid/row"; 16 | @import "grid/shift"; 17 | @import "grid/pad"; 18 | @import "grid/fill-parent"; 19 | @import "grid/media"; 20 | @import "grid/reset-display"; 21 | @import "grid/to-deprecate"; 22 | @import "grid/visual-grid"; 23 | @import "grid/display-context"; 24 | @import "grid/direction-context"; 25 | -------------------------------------------------------------------------------- /assets/static/js/webbkoll-30-app.js: -------------------------------------------------------------------------------- 1 | document.addEventListener("DOMContentLoaded", function(event) { 2 | var tables = document.querySelectorAll('[data-sortable]'), i; 3 | for (i = 0; i < tables.length; ++i) { 4 | new Tablesort(tables[i]); 5 | } 6 | }); 7 | 8 | window.addEventListener("load", function(event) { 9 | // The a11y elements ("How to...") mess up scrolling to fragment identifiers 10 | // (e.g. #cookies) on initial page load, at least in FF; this is a workaround 11 | // until I figure out something better. 12 | if (window.location.hash) { 13 | document.getElementById(window.location.hash.substring(1)).scrollIntoView(); 14 | } 15 | }); 16 | -------------------------------------------------------------------------------- /assets/scss/bourbon/bourbon/utilities/_gamma.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Performs gamma correction on a single color channel. 4 | /// 5 | /// Note that the calculation is approximate if a `pow()` is not available. 6 | /// 7 | /// @argument {number (0-1)} $channel 8 | /// 9 | /// @return {number (0-1)} 10 | /// 11 | /// @access private 12 | 13 | @function _gamma($channel) { 14 | @if $channel < 0.03928 { 15 | @return $channel / 12.92; 16 | } @else { 17 | $c: ($channel + 0.055) / 1.055; 18 | @if function-exists("pow") { 19 | @return pow($c, 2.4); 20 | } @else { 21 | @return 0.56 * $c * $c * $c + 0.44 * $c * $c; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /test/fixtures/test_content_sri_impl_external_http.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /test/support/model_case.ex: -------------------------------------------------------------------------------- 1 | defmodule Webbkoll.ModelCase do 2 | @moduledoc """ 3 | This module defines the test case to be used by 4 | model tests. 5 | 6 | You may define functions here to be used as helpers in 7 | your model tests. See `errors_on/2`'s definition as reference. 8 | 9 | Finally, if the test case interacts with the database, 10 | it cannot be async. For this reason, every test runs 11 | inside a transaction which is reset at the beginning 12 | of the test unless the test case is marked as async. 13 | """ 14 | 15 | use ExUnit.CaseTemplate 16 | 17 | using do 18 | quote do 19 | import Webbkoll.ModelCase 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /lib/webbkoll_web/templates/site/_raw_headers.html.heex: -------------------------------------------------------------------------------- 1 |
2 |

3 | <%= gettext "Raw headers" %> 4 | <%= anchor_link("raw-headers") %> 5 |

6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | <%= for {header, value} <- @site.data.headers do %> 16 | 17 | 18 | 19 | 20 | <% end %> 21 | 22 |
<%= gettext("Header") %><%= gettext("Value") %>
<%= header %><%= value %>
23 |
-------------------------------------------------------------------------------- /lib/webbkoll/cronjobs.ex: -------------------------------------------------------------------------------- 1 | defmodule Webbkoll.CronJobs do 2 | require Logger 3 | alias Webbkoll.Sites 4 | 5 | @max_attempts Application.compile_env(:webbkoll, :max_attempts) 6 | 7 | def find_and_remove_stuck_records do 8 | Logger.info("Checking for stuck records") 9 | sites_processing = Sites.get_sites_by(%{status: "processing"}) 10 | 11 | Enum.each(sites_processing, fn {id, site} -> 12 | if System.system_time(:microsecond) - site.updated_at > 40_000_000 && 13 | site.try_count >= @max_attempts do 14 | Sites.update_site(id, %{ 15 | status: "failed", 16 | status_message: "Server error on our side." 17 | }) 18 | end 19 | end) 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /assets/scss/bourbon/bourbon/library/_overflow-wrap.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Outputs the `overflow-wrap` property and its legacy name `word-wrap` to 4 | /// support browsers that do not yet use `overflow-wrap`. 5 | /// 6 | /// @argument {string} $wrap [break-word] 7 | /// Accepted CSS values are `normal`, `break-word`, `inherit`, `initial`, 8 | /// or `unset`. 9 | /// 10 | /// @example scss 11 | /// .wrapper { 12 | /// @include overflow-wrap; 13 | /// } 14 | /// 15 | /// // CSS Output 16 | /// .wrapper { 17 | /// word-wrap: break-word; 18 | /// overflow-wrap: break-word; 19 | /// } 20 | 21 | @mixin overflow-wrap($wrap: break-word) { 22 | word-wrap: $wrap; 23 | overflow-wrap: $wrap; 24 | } 25 | -------------------------------------------------------------------------------- /lib/webbkoll_web/views/layout_view.ex: -------------------------------------------------------------------------------- 1 | defmodule WebbkollWeb.LayoutView do 2 | use WebbkollWeb, :view 3 | 4 | @webbkoll_version Application.compile_env(:webbkoll, :version) 5 | @webbkoll_locales Application.compile_env(:webbkoll, :locales) 6 | 7 | # Yes this is a little ugly 8 | def path_helper(conn, lang) do 9 | if conn.private[:phoenix_controller] == WebbkollWeb.SiteController do 10 | Routes.site_path(conn, conn.private[:phoenix_action], lang, conn.query_params) 11 | else 12 | Routes.page_path(conn, conn.private[:phoenix_action], lang, conn.query_params) 13 | end 14 | end 15 | 16 | def webbkoll_version(), do: @webbkoll_version 17 | def webbkoll_locales(), do: @webbkoll_locales 18 | end 19 | -------------------------------------------------------------------------------- /assets/scss/bourbon/bourbon/utilities/_assign-inputs.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Append pseudo-classes to a selector(s). 4 | /// 5 | /// @argument {list | string} $inputs 6 | /// A selector, or list of selectors, to apply the pseudo-class to. 7 | /// 8 | /// @argument {pseudo-class} $pseudo [null] 9 | /// The pseudo-class to be appended. 10 | /// 11 | /// @return {list} 12 | /// 13 | /// @access private 14 | 15 | @function _assign-inputs( 16 | $inputs, 17 | $pseudo: null 18 | ) { 19 | $list: (); 20 | 21 | @each $input in $inputs { 22 | $input: unquote($input); 23 | $input: if($pseudo, $input + ":" + $pseudo, $input); 24 | $list: append($list, $input, comma); 25 | } 26 | 27 | @return $list; 28 | } 29 | -------------------------------------------------------------------------------- /assets/scss/bourbon/bourbon/helpers/_scales.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | //// 4 | /// Pre-defined scales for use with the `modular-scale` function. 5 | /// 6 | /// @type number (unitless) 7 | /// 8 | /// @see {function} modular-scale 9 | //// 10 | 11 | $minor-second: 1.067; 12 | $major-second: 1.125; 13 | $minor-third: 1.2; 14 | $major-third: 1.25; 15 | $perfect-fourth: 1.333; 16 | $augmented-fourth: 1.414; 17 | $perfect-fifth: 1.5; 18 | $minor-sixth: 1.6; 19 | $golden: 1.618; 20 | $major-sixth: 1.667; 21 | $minor-seventh: 1.778; 22 | $major-seventh: 1.875; 23 | $octave: 2; 24 | $major-tenth: 2.5; 25 | $major-eleventh: 2.667; 26 | $major-twelfth: 3; 27 | $double-octave: 4; 28 | -------------------------------------------------------------------------------- /ansible/templates/Caddyfile.j2: -------------------------------------------------------------------------------- 1 | # If caddy_prefix is empty, Caddy will try to get a TLS certificate for webbkoll_host and redirect http:// -> https://. 2 | # If caddy_prefix is "http://", Caddy will just listen to port 80. 3 | {{ caddy_prefix }}{{ webbkoll_host }} { 4 | reverse_proxy 127.0.0.1:4000 5 | header { 6 | -Server 7 | Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" 8 | 9 | # Webbkoll itself sets the headers below. Kept here for reference. 10 | #X-Content-Type-Options "nosniff" 11 | #X-Frame-Options "DENY" 12 | #Referrer-Policy "no-referrer" 13 | #Content-Security-Policy "default-src 'self'; frame-ancestors 'none'; base-uri 'none'; form-action 'self'" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /assets/scss/bourbon/bourbon/utilities/_lightness.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Programatically determines the lightness of a color. 4 | /// 5 | /// @argument {color (hex)} $hex-color 6 | /// 7 | /// @return {number (0-1)} 8 | /// 9 | /// @example scss 10 | /// _lightness($color) 11 | /// 12 | /// @access private 13 | 14 | @function _lightness($hex-color) { 15 | $-local-red-raw: red(rgba($hex-color, 1)); 16 | $-local-green-raw: green(rgba($hex-color, 1)); 17 | $-local-blue-raw: blue(rgba($hex-color, 1)); 18 | 19 | $-local-red: _gamma($-local-red-raw / 255); 20 | $-local-green: _gamma($-local-green-raw / 255); 21 | $-local-blue: _gamma($-local-blue-raw / 255); 22 | 23 | @return $-local-red * 0.2126 + $-local-green * 0.7152 + $-local-blue * 0.0722; 24 | } 25 | -------------------------------------------------------------------------------- /assets/scss/.sass-cache/c5b9bd97b08c64c7fb937eb29bc46d18ccdc9322/style.scssc: -------------------------------------------------------------------------------- 1 | 3.4.21 (Selective Steve) 2 | a88905fcc93968f3a6914143474887d400919d3d 3 | o:Sass::Tree::RootNode :@children[o:Sass::Tree::ImportNode :@imported_filenameI"bourbon/bourbon:ET;[:@template0: 4 | @linei:@source_rangeo:Sass::Source::Range :@start_poso:Sass::Source::Position; i: @offseti: @end_poso;; i;i: 5 | @fileI"style.scss; T:@importero: Sass::Importers::Filesystem: 6 | @rootI"A/home/andersju/jobb/dataskydd/syzygy/bourbontest/stylesheets; T:@real_rootI"A/home/andersju/jobb/dataskydd/syzygy/bourbontest/stylesheets; T:@same_name_warningso:Set: 7 | @hash}F: @options{:@imported_file0; 8 | I" @import "bourbon/bourbon"; 9 | ; T; i; o; ;o;; i;i;o;; i;i;@ ;@:@has_childrenT;@ -------------------------------------------------------------------------------- /assets/scss/bourbon/bourbon/library/_border-width.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Provides a concise, one-line method for setting `border-width` on specific 4 | /// edges of a box. Use a `null` value to “skip” edges of the box with standard 5 | /// CSS shorthand. 6 | /// 7 | /// @argument {list} $values 8 | /// List of border widths; accepts CSS shorthand. 9 | /// 10 | /// @example scss 11 | /// .element { 12 | /// @include border-width(1em null 20px); 13 | /// } 14 | /// 15 | /// // CSS Output 16 | /// .element { 17 | /// border-bottom-width: 20px; 18 | /// border-top-width: 1em; 19 | /// } 20 | /// 21 | /// @require {mixin} _directional-property 22 | 23 | @mixin border-width($values) { 24 | @include _directional-property(border, width, $values); 25 | } 26 | -------------------------------------------------------------------------------- /assets/scss/bourbon/bourbon/library/_border-style.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Provides a concise, one-line method for setting `border-style` on specific 4 | /// edges of a box. Use a `null` value to “skip” edges of the box with standard 5 | /// CSS shorthand. 6 | /// 7 | /// @argument {list} $values 8 | /// List of border styles; accepts CSS shorthand. 9 | /// 10 | /// @example scss 11 | /// .element { 12 | /// @include border-style(dashed null solid); 13 | /// } 14 | /// 15 | /// // CSS Output 16 | /// .element { 17 | /// border-bottom-style: solid; 18 | /// border-top-style: dashed; 19 | /// } 20 | /// 21 | /// @require {mixin} _directional-property 22 | 23 | @mixin border-style($values) { 24 | @include _directional-property(border, style, $values); 25 | } 26 | -------------------------------------------------------------------------------- /assets/scss/_tablesort.scss: -------------------------------------------------------------------------------- 1 | th[role=columnheader]:not(.no-sort) { 2 | cursor: pointer; 3 | } 4 | 5 | th[role=columnheader]:not(.no-sort):after { 6 | content: ''; 7 | float: right; 8 | margin-top: 7px; 9 | border-width: 0 4px 4px; 10 | border-style: solid; 11 | border-color: #404040 transparent; 12 | visibility: hidden; 13 | opacity: 0; 14 | -ms-user-select: none; 15 | -webkit-user-select: none; 16 | -moz-user-select: none; 17 | user-select: none; 18 | } 19 | 20 | th[aria-sort=ascending]:not(.no-sort):after { 21 | border-bottom: none; 22 | border-width: 4px 4px 0; 23 | } 24 | 25 | th[aria-sort]:not(.no-sort):after { 26 | visibility: visible; 27 | opacity: 0.4; 28 | } 29 | 30 | th[role=columnheader]:not(.no-sort):hover:after { 31 | visibility: visible; 32 | opacity: 1; 33 | } 34 | -------------------------------------------------------------------------------- /assets/scss/bourbon/bourbon/library/_tint.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Mixes a color with white. 4 | /// 5 | /// @argument {color} $color 6 | /// 7 | /// @argument {number (percentage)} $percent 8 | /// The amount of white to be mixed in. 9 | /// 10 | /// @return {color} 11 | /// 12 | /// @example scss 13 | /// .element { 14 | /// background-color: tint(#6ecaa6, 40%); 15 | /// } 16 | /// 17 | /// // CSS Output 18 | /// .element { 19 | /// background-color: #a8dfc9; 20 | /// } 21 | 22 | @function tint( 23 | $color, 24 | $percent 25 | ) { 26 | @if not _is-color($color) { 27 | @error "`#{$color}` is not a valid color for the `$color` argument in " + 28 | "the `tint` mixin."; 29 | } @else { 30 | @return mix(#fff, $color, $percent); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /assets/scss/neat/grid/_pad.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Adds padding to the element. 4 | /// 5 | /// @param {List} $padding [flex-gutter()] 6 | /// A list of padding value(s) to use. Passing `default` in the list will result in using the gutter width as a padding value. 7 | /// 8 | /// @example scss - Usage 9 | /// .element { 10 | /// @include pad(30px -20px 10px default); 11 | /// } 12 | /// 13 | /// @example css - CSS Output 14 | /// .element { 15 | /// padding: 30px -20px 10px 2.35765%; 16 | /// } 17 | 18 | @mixin pad($padding: flex-gutter()) { 19 | $padding-list: null; 20 | @each $value in $padding { 21 | $value: if($value == 'default', flex-gutter(), $value); 22 | $padding-list: join($padding-list, $value); 23 | } 24 | padding: $padding-list; 25 | } 26 | -------------------------------------------------------------------------------- /assets/scss/bourbon/bourbon/library/_shade.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Mixes a color with black. 4 | /// 5 | /// @argument {color} $color 6 | /// 7 | /// @argument {number (percentage)} $percent 8 | /// The amount of black to be mixed in. 9 | /// 10 | /// @return {color} 11 | /// 12 | /// @example scss 13 | /// .element { 14 | /// background-color: shade(#ffbb52, 60%); 15 | /// } 16 | /// 17 | /// // CSS Output 18 | /// .element { 19 | /// background-color: #664a20; 20 | /// } 21 | 22 | @function shade( 23 | $color, 24 | $percent 25 | ) { 26 | @if not _is-color($color) { 27 | @error "`#{$color}` is not a valid color for the `$color` argument in " + 28 | "the `shade` mixin."; 29 | } @else { 30 | @return mix(#000, $color, $percent); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /assets/scss/neat/grid/_display-context.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Changes the display property used by other mixins called in the code block argument. 4 | /// 5 | /// @param {String} $display [block] 6 | /// Display value to be used within the block. Can be `table` or `block`. 7 | /// 8 | /// @example scss 9 | /// @include display-context(table) { 10 | /// .display-table { 11 | /// @include span-columns(6); 12 | /// } 13 | /// } 14 | /// 15 | /// @example css 16 | /// .display-table { 17 | /// display: table-cell; 18 | /// ... 19 | /// } 20 | 21 | @mixin display-context($display: block) { 22 | $scope-display: $container-display-table; 23 | $container-display-table: $display == table !global; 24 | 25 | @content; 26 | 27 | $container-display-table: $scope-display !global; 28 | } 29 | -------------------------------------------------------------------------------- /lib/webbkoll_web/gettext.ex: -------------------------------------------------------------------------------- 1 | defmodule WebbkollWeb.Gettext do 2 | @moduledoc """ 3 | A module providing Internationalization with a gettext-based API. 4 | 5 | By using [Gettext](http://hexdocs.pm/gettext), 6 | your module gains a set of macros for translations, for example: 7 | 8 | import Webbkoll.Gettext 9 | 10 | # Simple translation 11 | gettext "Here is the string to translate" 12 | 13 | # Plural translation 14 | ngettext "Here is the string to translate", 15 | "Here are the strings to translate", 16 | 3 17 | 18 | # Domain-based translation 19 | dgettext "errors", "Here is the error message to translate" 20 | 21 | See the [Gettext Docs](http://hexdocs.pm/gettext) for detailed usage. 22 | """ 23 | use Gettext, otp_app: :webbkoll 24 | end 25 | -------------------------------------------------------------------------------- /assets/scss/bourbon/bourbon/library/_border-color.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Provides a concise, one-line method for setting `border-color` on specific 4 | /// edges of a box. Use a `null` value to “skip” edges of the box with standard 5 | /// CSS shorthand. 6 | /// 7 | /// @argument {list} $values 8 | /// List of colors; accepts CSS shorthand. 9 | /// 10 | /// @example scss 11 | /// .element { 12 | /// @include border-color(#a60b55 #76cd9c null #e8ae1a); 13 | /// } 14 | /// 15 | /// // CSS Output 16 | /// .element { 17 | /// border-left-color: #e8ae1a; 18 | /// border-right-color: #76cd9c; 19 | /// border-top-color: #a60b55; 20 | /// } 21 | /// 22 | /// @require {mixin} _directional-property 23 | 24 | @mixin border-color($values) { 25 | @include _directional-property(border, color, $values); 26 | } 27 | -------------------------------------------------------------------------------- /test/fixtures/test_parse_http_equiv_headers_csp_multiple_http_equiv1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Title 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /assets/scss/bourbon/bourbon/library/_prefixer.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Generates vendor prefixes. 4 | /// 5 | /// @argument {string} $property 6 | /// Property to prefix. 7 | /// 8 | /// @argument {string} $value 9 | /// Value to use. 10 | /// 11 | /// @argument {list} $prefixes 12 | /// Vendor prefixes to output. 13 | /// 14 | /// @example scss 15 | /// .element { 16 | /// @include prefixer(appearance, none, ("webkit", "moz")); 17 | /// } 18 | /// 19 | /// // CSS Output 20 | /// .element { 21 | /// -webkit-appearance: none; 22 | /// -moz-appearance: none; 23 | /// appearance: none; 24 | /// } 25 | /// 26 | /// @author Hugo Giraudel 27 | 28 | @mixin prefixer( 29 | $property, 30 | $value, 31 | $prefixes: () 32 | ) { 33 | @each $prefix in $prefixes { 34 | #{"-" + $prefix + "-" + $property}: $value; 35 | } 36 | #{$property}: $value; 37 | } 38 | -------------------------------------------------------------------------------- /assets/scss/neat/settings/_visual-grid.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Displays the visual grid when set to true. The overlaid grid may be few pixels off depending on the browser's rendering engine and pixel rounding algorithm. Set with the `!global` flag. 4 | /// 5 | /// @type Bool 6 | 7 | $visual-grid: false !default; 8 | 9 | /// Sets the visual grid color. Set with `!global` flag. 10 | /// 11 | /// @type Color 12 | 13 | $visual-grid-color: #eee !default; 14 | 15 | /// Sets the `z-index` property of the visual grid. Can be `back` (behind content) or `front` (in front of content). Set with `!global` flag. 16 | /// 17 | /// @type String 18 | 19 | $visual-grid-index: back !default; 20 | 21 | /// Sets the opacity property of the visual grid. Set with `!global` flag. 22 | /// 23 | /// @type Number (unitless) 24 | 25 | $visual-grid-opacity: 0.4 !default; 26 | 27 | $visual-grid-breakpoints: () !default; 28 | -------------------------------------------------------------------------------- /assets/scss/bourbon/bourbon/library/_value-prefixer.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Generates vendor prefixes for values. 4 | /// 5 | /// @argument {string} $property 6 | /// Property to use. 7 | /// 8 | /// @argument {string} $value 9 | /// Value to prefix. 10 | /// 11 | /// @argument {list} $prefixes 12 | /// Vendor prefixes to output. 13 | /// 14 | /// @example scss 15 | /// .element { 16 | /// @include value-prefixer(cursor, grab, ("webkit", "moz")); 17 | /// } 18 | /// 19 | /// // CSS Output 20 | /// .element { 21 | /// cursor: -webkit-grab; 22 | /// cursor: -moz-grab; 23 | /// cursor: grab; 24 | /// } 25 | /// 26 | /// @author Matthew Tobiasz 27 | 28 | @mixin value-prefixer( 29 | $property, 30 | $value, 31 | $prefixes: () 32 | ) { 33 | @each $prefix in $prefixes { 34 | #{$property}: #{"-" + $prefix + "-" + $value}; 35 | } 36 | #{$property}: $value; 37 | } 38 | -------------------------------------------------------------------------------- /assets/scss/bourbon/bourbon/utilities/_contrast-ratio.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Programatically determines the contrast ratio between two colors. 4 | /// 5 | /// Note that the alpha channel is ignored. 6 | /// 7 | /// @link https://goo.gl/54htLV 8 | /// 9 | /// @argument {color (hex)} $color-1 10 | /// 11 | /// @argument {color (hex)} $color-2 12 | /// 13 | /// @return {number (1-21)} 14 | /// 15 | /// @example scss 16 | /// _contrast-ratio(black, white) 17 | /// 18 | /// @require {function} _lightness 19 | /// 20 | /// @access private 21 | 22 | @function _contrast-ratio($color-1, $color-2) { 23 | $-local-lightness-1: _lightness($color-1) + 0.05; 24 | $-local-lightness-2: _lightness($color-2) + 0.05; 25 | 26 | @if $-local-lightness-1 > $-local-lightness-2 { 27 | @return $-local-lightness-1 / $-local-lightness-2; 28 | } @else { 29 | @return $-local-lightness-2 / $-local-lightness-1; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /lib/webbkoll_web/templates/site/results.html.heex: -------------------------------------------------------------------------------- 1 |
2 | <%= render "_results_header.html", site: @site, conn: @conn %> 3 | 4 |
5 | <%= render "_https.html", site: @site %> 6 | 7 | <%= render "_hsts.html", site: @site %> 8 | 9 | <%= render "_csp.html", site: @site %> 10 | 11 | <%= render "_ext_report.html", site: @site %> 12 | 13 | <%= render "_referrers.html", site: @site %> 14 | 15 | <%= render "_sri.html", site: @site %> 16 | 17 | <%= render "_headers.html", site: @site %> 18 | 19 | <%= render "_cookies.html", site: @site %> 20 | 21 | <%= render "_localstorage.html", site: @site %> 22 | 23 | <%= render "_requests.html", site: @site %> 24 | 25 | <%= render "_geolocation.html", site: @site, conn: @conn %> 26 | 27 | <%= render "_raw_headers.html", site: @site %> 28 | 29 | <%= render "_what.html", conn: @conn %> 30 |
31 |
-------------------------------------------------------------------------------- /lib/webbkoll_web/controllers/controller_helpers.ex: -------------------------------------------------------------------------------- 1 | defmodule WebbkollWeb.ControllerHelpers do 2 | import Plug.Conn 3 | import Phoenix.Controller 4 | import WebbkollWeb.Gettext 5 | 6 | alias Webbkoll.Sites 7 | 8 | @backends Application.compile_env(:webbkoll, :backends) 9 | 10 | def enqueue_site(conn, url) do 11 | {queue, settings} = Enum.random(@backends) 12 | 13 | {:ok, site} = Sites.add_site(url) 14 | 15 | { 16 | :perform, 17 | [ 18 | site.id, 19 | url, 20 | conn.params["refresh"], 21 | settings.url 22 | ] 23 | } 24 | |> Honeydew.async(queue) 25 | 26 | site 27 | end 28 | 29 | def render_error(conn, status, error_message) do 30 | conn 31 | |> put_status(status) 32 | |> put_view(WebbkollWeb.ErrorView) 33 | |> render(:"#{status}", error_message: error_message, page_title: gettext("Error")) 34 | |> halt() 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /test/support/conn_case.ex: -------------------------------------------------------------------------------- 1 | defmodule WebbkollWeb.ConnCase do 2 | @moduledoc """ 3 | This module defines the test case to be used by 4 | tests that require setting up a connection. 5 | 6 | Such tests rely on `Phoenix.ConnTest` and also 7 | imports other functionality to make it easier 8 | to build and query models. 9 | 10 | Finally, if the test case interacts with the database, 11 | it cannot be async. For this reason, every test runs 12 | inside a transaction which is reset at the beginning 13 | of the test unless the test case is marked as async. 14 | """ 15 | 16 | use ExUnit.CaseTemplate 17 | 18 | using do 19 | quote do 20 | # Import conveniences for testing with connections 21 | import Plug.Conn 22 | import Phoenix.ConnTest 23 | import WebbkollWeb.Router.Helpers 24 | 25 | # The default endpoint for testing 26 | @endpoint WebbkollWeb.Endpoint 27 | end 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /assets/scss/bourbon/bourbon/utilities/_unpack-shorthand.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Transforms shorthand that can range from 1-to-4 values to be 4 values. 4 | /// 5 | /// @argument {list} $shorthand 6 | /// 7 | /// @example scss 8 | /// .element { 9 | /// margin: _unpack-shorthand(1em 2em); 10 | /// } 11 | /// 12 | /// // CSS Output 13 | /// .element { 14 | /// margin: 1em 2em 1em 2em; 15 | /// } 16 | /// 17 | /// @access private 18 | 19 | @function _unpack-shorthand($shorthand) { 20 | @if length($shorthand) == 1 { 21 | @return nth($shorthand, 1) nth($shorthand, 1) nth($shorthand, 1) nth($shorthand, 1); 22 | } @else if length($shorthand) == 2 { 23 | @return nth($shorthand, 1) nth($shorthand, 2) nth($shorthand, 1) nth($shorthand, 2); 24 | } @else if length($shorthand) == 3 { 25 | @return nth($shorthand, 1) nth($shorthand, 2) nth($shorthand, 3) nth($shorthand, 2); 26 | } @else { 27 | @return $shorthand; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /assets/scss/bourbon/bourbon/library/_ellipsis.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Truncates text and adds an ellipsis to represent overflow. 4 | /// 5 | /// @argument {number} $width [100%] 6 | /// The `max-width` for the string to respect before being truncated. 7 | /// 8 | /// @argument {string} $display [inline-block] 9 | /// Sets the display-value of the element. 10 | /// 11 | /// @example scss 12 | /// .element { 13 | /// @include ellipsis; 14 | /// } 15 | /// 16 | /// // CSS Output 17 | /// .element { 18 | /// display: inline-block; 19 | /// max-width: 100%; 20 | /// overflow: hidden; 21 | /// text-overflow: ellipsis; 22 | /// white-space: nowrap; 23 | /// word-wrap: normal; 24 | /// } 25 | 26 | @mixin ellipsis( 27 | $width: 100%, 28 | $display: inline-block 29 | ) { 30 | display: $display; 31 | max-width: $width; 32 | overflow: hidden; 33 | text-overflow: ellipsis; 34 | white-space: nowrap; 35 | word-wrap: normal; 36 | } 37 | -------------------------------------------------------------------------------- /assets/scss/bourbon/bourbon/library/_padding.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Provides a concise method for targeting `padding` on specific sides of a 4 | /// box. Use a `null` value to “skip” a side. 5 | /// 6 | /// @argument {list} $values 7 | /// List of padding values; accepts CSS shorthand. 8 | /// 9 | /// @example scss 10 | /// .element-one { 11 | /// @include padding(null 1rem); 12 | /// } 13 | /// 14 | /// // CSS Output 15 | /// .element-one { 16 | /// padding-left: 1rem; 17 | /// padding-right: 1rem; 18 | /// } 19 | /// 20 | /// @example scss 21 | /// .element-two { 22 | /// @include padding(10vh null 10px 5%); 23 | /// } 24 | /// 25 | /// // CSS Output 26 | /// .element-two { 27 | /// padding-bottom: 10px; 28 | /// padding-left: 5%; 29 | /// padding-top: 10vh; 30 | /// } 31 | /// 32 | /// @require {mixin} _directional-property 33 | 34 | @mixin padding($values) { 35 | @include _directional-property(padding, null, $values); 36 | } 37 | -------------------------------------------------------------------------------- /assets/scss/.sass-cache/74571de3e827f0001966c84f665e8974ed75748e/_px-to-em.scssc: -------------------------------------------------------------------------------- 1 | 3.4.21 (Selective Steve) 2 | 14880c373629b1e71abf17d6dc147ca56126856a 3 | o:Sass::Tree::RootNode :@children[o:Sass::Tree::VariableNode : 4 | @nameI" em-base:ET: 5 | @expro: Sass::Script::Tree::Literal : @valueo: Sass::Script::Value::Number 6 | ; i:@numerator_units[I"px; T:@denominator_units[: @options{:@originalI" 16px; T: 7 | @linei:@source_rangeo:Sass::Source::Range :@start_poso:Sass::Source::Position;i: @offseti: @end_poso;;i;i: 8 | @fileI"$bourbon/settings/_px-to-em.scss; T:@importero: Sass::Importers::Filesystem: 9 | @rootI"A/home/andersju/jobb/dataskydd/syzygy/bourbontest/stylesheets; T:@real_rootI"A/home/andersju/jobb/dataskydd/syzygy/bourbontest/stylesheets; T:@same_name_warningso:Set: 10 | @hash}F:@filename@: @guardedT: @global0;[;i;o; ;o;;i;i;o;;i;i;@;@;@:@templateI"$em-base: 16px !default; 11 | ; T;i;o; ;o;;i;i;o;;i;i;@;@:@has_childrenT;@ -------------------------------------------------------------------------------- /assets/scss/bourbon/bourbon/library/_margin.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Provides a concise, one-line method for setting `margin` on specific edges 4 | /// of a box. Use a `null` value to “skip” edges of the box with standard 5 | /// CSS shorthand. 6 | /// 7 | /// @argument {list} $values 8 | /// List of margin values; accepts CSS shorthand. 9 | /// 10 | /// @example scss 11 | /// .element { 12 | /// @include margin(null auto); 13 | /// } 14 | /// 15 | /// // CSS Output 16 | /// .element { 17 | /// margin-left: auto; 18 | /// margin-right: auto; 19 | /// } 20 | /// 21 | /// @example scss 22 | /// .element { 23 | /// @include margin(10px 3em 20vh null); 24 | /// } 25 | /// 26 | /// // CSS Output 27 | /// .element { 28 | /// margin-bottom: 20vh; 29 | /// margin-right: 3em; 30 | /// margin-top: 10px; 31 | /// } 32 | /// 33 | /// @require {mixin} _directional-property 34 | 35 | @mixin margin($values) { 36 | @include _directional-property(margin, null, $values); 37 | } 38 | -------------------------------------------------------------------------------- /assets/scss/neat/grid/_direction-context.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Changes the direction property used by other mixins called in the code block argument. 4 | /// 5 | /// @param {String} $direction [left-to-right] 6 | /// Layout direction to be used within the block. Can be `left-to-right` or `right-to-left`. 7 | /// 8 | /// @example scss - Usage 9 | /// @include direction-context(right-to-left) { 10 | /// .right-to-left-block { 11 | /// @include span-columns(6); 12 | /// } 13 | /// } 14 | /// 15 | /// @example css - CSS Output 16 | /// .right-to-left-block { 17 | /// float: right; 18 | /// ... 19 | /// } 20 | 21 | @mixin direction-context($direction: left-to-right) { 22 | $scope-direction: $layout-direction; 23 | 24 | @if to-lower-case($direction) == "left-to-right" { 25 | $layout-direction: LTR !global; 26 | } @else if to-lower-case($direction) == "right-to-left" { 27 | $layout-direction: RTL !global; 28 | } 29 | 30 | @content; 31 | 32 | $layout-direction: $scope-direction !global; 33 | } 34 | -------------------------------------------------------------------------------- /config/test.exs: -------------------------------------------------------------------------------- 1 | import Config 2 | 3 | # We don't run a server during test. If one is required, 4 | # you can enable the server option below. 5 | config :webbkoll, WebbkollWeb.Endpoint, 6 | http: [port: 4001], 7 | server: false, 8 | debug_errors: false 9 | 10 | # Print only warnings and errors during test 11 | config :logger, level: :warn 12 | 13 | config :webbkoll, 14 | backends: [ 15 | {Webbkoll.Queue.Q1, %{concurrency: 5, url: "http://localhost:8100/"}}, 16 | ], 17 | max_attempts: 2, 18 | # validate_urls: If true, only check URLs with a valid domain name 19 | # (i.e. ones with a TLD in the Public Suffix List), 20 | # and only the standard HTTP/HTTPS ports. 21 | validate_urls: true, 22 | # rate_limit_client: An IP address can make new site checks 23 | # during milliseconds. 24 | # rate_limit_host: The tool will query a specific host no more than 25 | # times during milliseconds. 26 | # See https://github.com/grempe/ex_rated 27 | rate_limit_client: %{"scale" => 60_000, "limit" => 20}, 28 | rate_limit_host: %{"scale" => 60_000, "limit" => 5} 29 | -------------------------------------------------------------------------------- /assets/scss/neat/grid/_outer-container.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Makes an element a outer container by centering it in the viewport, clearing its floats, and setting its `max-width`. 4 | /// Although optional, using `outer-container` is recommended. The mixin can be called on more than one element per page, as long as they are not nested. 5 | /// 6 | /// @param {Number [unit]} $local-max-width [$max-width] 7 | /// Max width to be applied to the element. Can be a percentage or a measure. 8 | /// 9 | /// @example scss - Usage 10 | /// .element { 11 | /// @include outer-container(100%); 12 | /// } 13 | /// 14 | /// @example css - CSS Output 15 | /// .element { 16 | /// max-width: 100%; 17 | /// margin-left: auto; 18 | /// margin-right: auto; 19 | /// } 20 | /// 21 | /// .element::after { 22 | /// clear: both; 23 | /// content: ""; 24 | /// display: table; 25 | /// } 26 | 27 | @mixin outer-container($local-max-width: $max-width) { 28 | @include clearfix; 29 | max-width: $local-max-width; 30 | margin: { 31 | left: auto; 32 | right: auto; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Anders Jensen-Urstad 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /lib/webbkoll_web/templates/site/_what.html.heex: -------------------------------------------------------------------------------- 1 |
2 |

3 | <%= gettext "What this tool checks (and doesn't check) " %> 4 | <%= anchor_link("what") %> 5 |

6 | 7 |

<%= gettext("This tool attempts to simulate what happens when a user visits a specified page with a typical browser. The browser has no addons/extensions installed, and Do Not Track (DNT) is not enabled, since this is the default setting in most browsers.") %>

8 | 9 |

<%= gettext("External files such as images, scripts and CSS are loaded, but the tool performs no interactions with the page — no links are clicked, no forms are submitted.") %>

10 | 11 |

<%= gettext("Disclaimer: The results presented here might not be 100% correct. Bugs happen. This tool is meant to be used by site owners as a starting point for improvements, not as a rigorous analysis.") %>

12 | 13 |

<%= gettext(~s|Text about HTTPS partly adapted from the CIO Council's The HTTPS-Only Standard (public domain). See here for more information.|, about: Routes.page_path(@conn, :about, @conn.assigns.locale)) |> raw() %>

14 |
-------------------------------------------------------------------------------- /assets/scss/base/_variables.scss: -------------------------------------------------------------------------------- 1 | .ds-orange { color: #f66931; } 2 | .black { color: black; } 3 | .light { font-weight: 300; } 4 | .semibold { font-weight: 600; } 5 | .bold { font-weight: 700; } 6 | 7 | // Typography 8 | $base-font-family: $font-stack-system; 9 | $heading-font-family: $font-stack-serif; 10 | 11 | // Line height 12 | $base-line-height: $magic-number; 13 | $heading-line-height: 1.2; 14 | 15 | // Other Sizes 16 | $base-border-radius: 3px; 17 | $base-spacing: $magic-number; 18 | $small-spacing: $base-spacing / 2; 19 | $base-z-index: 0; 20 | 21 | // Colors 22 | $blue: #1565c0; 23 | $dark-gray: #333; 24 | $medium-gray: #999; 25 | $light-gray: #ddd; 26 | 27 | // Font Colors 28 | $base-font-color: $dark-gray; 29 | $action-color: $blue; 30 | 31 | // Border 32 | $base-border-color: $light-gray; 33 | $base-border: 1px solid $base-border-color; 34 | 35 | // Background Colors 36 | $viewport-background-color: #fff; 37 | 38 | // Focus 39 | $focus-outline-color: transparentize($action-color, 0.4); 40 | $focus-outline-width: 3px; 41 | $focus-outline: $focus-outline-width solid $focus-outline-color; 42 | $focus-outline-offset: 2px; 43 | 44 | // Animations 45 | $base-duration: 150ms; 46 | $base-timing: ease; 47 | -------------------------------------------------------------------------------- /config/dev.exs: -------------------------------------------------------------------------------- 1 | import Config 2 | 3 | # For development, we disable any cache and enable 4 | # debugging and code reloading. 5 | config :webbkoll, WebbkollWeb.Endpoint, 6 | http: [port: 4000], 7 | debug_errors: true, 8 | code_reloader: true, 9 | check_origin: false, 10 | secret_key_base: "IvzBctBrLEScfiglXkTgxhEA8+/A6Eyyc4xYhzgAepLUnv8L7gbL7WK4cU4gx5uJ", 11 | watchers: [] 12 | 13 | # Watch static and templates for browser reloading. 14 | config :webbkoll, WebbkollWeb.Endpoint, 15 | live_reload: [ 16 | patterns: [ 17 | ~r{priv/static/.*(js|css|png|jpeg|jpg|gif|svg)$}, 18 | ~r{priv/gettext/.*(po)$}, 19 | ~r{lib/webbkoll_web/(live|views)/.*(ex)$}, 20 | ~r{lib/webbkoll_web/templates/.*(eex)$} 21 | ] 22 | ] 23 | 24 | # Do not include metadata nor timestamps in development logs 25 | config :logger, :console, format: "[$level] $message\n", level: :warn 26 | 27 | # Set a higher stacktrace during development. 28 | # Do not configure such in production as keeping 29 | # and calculating stacktraces is usually expensive. 30 | config :phoenix, :stacktrace_depth, 20 31 | 32 | # Initialize plugs at runtime for faster development compilation 33 | config :phoenix, :plug_init_mode, :runtime 34 | -------------------------------------------------------------------------------- /assets/scss/bourbon/bourbon/utilities/_compact-shorthand.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | // scss-lint:disable ElsePlacement 4 | 5 | /// Transforms shorthand to its shortest possible form. 6 | /// 7 | /// @argument {list} $values 8 | /// List of directional values. 9 | /// 10 | /// @example scss 11 | /// $values: _compact-shorthand(10px 20px 10px 20px); 12 | /// 13 | /// // Output 14 | /// $values: 10px 20px; 15 | /// 16 | /// @return {list} 17 | /// 18 | /// @access private 19 | 20 | @function _compact-shorthand($values) { 21 | $output: null; 22 | 23 | $a: nth($values, 1); 24 | $b: if(length($values) < 2, $a, nth($values, 2)); 25 | $c: if(length($values) < 3, $a, nth($values, 3)); 26 | $d: if(length($values) < 2, $a, nth($values, if(length($values) < 4, 2, 4))); 27 | 28 | @if $a == 0 { $a: 0; } 29 | @if $b == 0 { $b: 0; } 30 | @if $c == 0 { $c: 0; } 31 | @if $d == 0 { $d: 0; } 32 | 33 | @if $a == $b and $a == $c and $a == $d { $output: $a; } 34 | @else if $a == $c and $b == $d { $output: $a $b; } 35 | @else if $b == $d { $output: $a $b $c; } 36 | @else { $output: $a $b $c $d; } 37 | 38 | @return $output; 39 | } 40 | -------------------------------------------------------------------------------- /assets/scss/neat/grid/_private.scss: -------------------------------------------------------------------------------- 1 | $parent-columns: $grid-columns !default; 2 | $fg-column: $column; 3 | $fg-gutter: $gutter; 4 | $fg-max-columns: $grid-columns; 5 | $container-display-table: false !default; 6 | $layout-direction: LTR !default; 7 | 8 | @function flex-grid($columns, $container-columns: $fg-max-columns) { 9 | $width: flex-width($columns); 10 | $container-width: flex-width($container-columns); 11 | @return percentage($width / $container-width); 12 | } 13 | 14 | @function flex-gutter($container-columns: $fg-max-columns, $gutter: $fg-gutter) { 15 | $container-width: flex-width($container-columns); 16 | @return percentage($gutter / $container-width); 17 | } 18 | 19 | @function flex-width($n, $column-width: $fg-column, $gutter-width: $fg-gutter) { 20 | @return $n * $column-width + ($n - 1) * $gutter-width; 21 | } 22 | 23 | @function get-parent-columns($columns) { 24 | @if $columns != $grid-columns { 25 | $parent-columns: $columns !global; 26 | } @else { 27 | $parent-columns: $grid-columns !global; 28 | } 29 | 30 | @return $parent-columns; 31 | } 32 | 33 | @function is-display-table($container-is-display-table, $display) { 34 | @return $container-is-display-table == true or $display == table; 35 | } 36 | -------------------------------------------------------------------------------- /assets/scss/base/_buttons.scss: -------------------------------------------------------------------------------- 1 | $_button-background-color: $action-color; 2 | $_button-background-color-hover: shade($action-color, 20%); 3 | 4 | #{$all-buttons} { 5 | appearance: none; 6 | background-color: $_button-background-color; 7 | border: 0; 8 | border-radius: $base-border-radius; 9 | color: contrast-switch($_button-background-color); 10 | cursor: pointer; 11 | display: inline-block; 12 | font-family: $base-font-family; 13 | font-size: 16px; 14 | -webkit-font-smoothing: antialiased; 15 | font-weight: 600; 16 | line-height: 1; 17 | padding: $small-spacing $base-spacing; 18 | text-align: center; 19 | text-decoration: none; 20 | transition: background-color $base-duration $base-timing; 21 | user-select: none; 22 | vertical-align: middle; 23 | white-space: nowrap; 24 | 25 | &:hover { 26 | background-color: $_button-background-color-hover; 27 | color: contrast-switch($_button-background-color-hover); 28 | } 29 | 30 | &:focus { 31 | outline: $focus-outline; 32 | outline-offset: $focus-outline-offset; 33 | } 34 | 35 | &:disabled { 36 | cursor: not-allowed; 37 | opacity: 0.5; 38 | 39 | &:hover { 40 | background-color: $_button-background-color; 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /assets/scss/bourbon/bourbon/library/_size.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Sets the `width` and `height` of the element in one statement. 4 | /// 5 | /// @argument {number (with unit) | string} $width 6 | /// 7 | /// @argument {number (with unit) | string} $height [$width] 8 | /// 9 | /// @example scss 10 | /// .first-element { 11 | /// @include size(2em); 12 | /// } 13 | /// 14 | /// // CSS Output 15 | /// .first-element { 16 | /// width: 2em; 17 | /// height: 2em; 18 | /// } 19 | /// 20 | /// @example scss 21 | /// .second-element { 22 | /// @include size(auto, 10em); 23 | /// } 24 | /// 25 | /// // CSS Output 26 | /// .second-element { 27 | /// width: auto; 28 | /// height: 10em; 29 | /// } 30 | /// 31 | /// @require {function} _is-size 32 | 33 | @mixin size( 34 | $width, 35 | $height: $width 36 | ) { 37 | @if _is-size($height) { 38 | height: $height; 39 | } @else { 40 | @error "`#{$height}` is not a valid length for the `$height` argument " + 41 | "in the `size` mixin."; 42 | } 43 | 44 | @if _is-size($width) { 45 | width: $width; 46 | } @else { 47 | @error "`#{$width}` is not a valid length for the `$width` argument " + 48 | "in the `size` mixin."; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /assets/scss/neat/grid/_visual-grid.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | @mixin grid-column-gradient($values...) { 4 | background-image: -webkit-linear-gradient(left, $values); 5 | background-image: -moz-linear-gradient(left, $values); 6 | background-image: -ms-linear-gradient(left, $values); 7 | background-image: -o-linear-gradient(left, $values); 8 | background-image: unquote("linear-gradient(to left, #{$values})"); 9 | } 10 | 11 | @if $visual-grid == true or $visual-grid == yes { 12 | body:before { 13 | @include grid-column-gradient(gradient-stops($grid-columns)); 14 | content: ""; 15 | display: inline-block; 16 | height: 100%; 17 | left: 0; 18 | margin: 0 auto; 19 | max-width: $max-width; 20 | opacity: $visual-grid-opacity; 21 | pointer-events: none; 22 | position: fixed; 23 | right: 0; 24 | width: 100%; 25 | 26 | @if $visual-grid-index == back { 27 | z-index: -1; 28 | } 29 | 30 | @else if $visual-grid-index == front { 31 | z-index: 9999; 32 | } 33 | 34 | @each $breakpoint in $visual-grid-breakpoints { 35 | @if $breakpoint { 36 | @include media($breakpoint) { 37 | @include grid-column-gradient(gradient-stops($grid-columns)); 38 | } 39 | } 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /assets/static/js/webbkoll-20-a11y-toggle.min.js: -------------------------------------------------------------------------------- 1 | !function(){"use strict";function t(t,e){return Array.prototype.slice.call((e||document).querySelectorAll(t))}function e(t){if(t.closest)return t.closest("[data-a11y-toggle]");for(;t;){if(1===t.nodeType&&t.hasAttribute("data-a11y-toggle"))return t;t=t.parentNode}return null}function a(t){var e=t&&n[t.getAttribute("aria-controls")];if(!e)return!1;var a=i["#"+e.id],r="false"===e.getAttribute("aria-hidden");e.setAttribute("aria-hidden",r),a.forEach(function(t){t.setAttribute("aria-expanded",!r)})}var r=0,i={},n={},o=function(e){i=t("[data-a11y-toggle]",e).reduce(function(t,e){var a="#"+e.getAttribute("data-a11y-toggle");return t[a]=t[a]||[],t[a].push(e),t},i);var a=Object.keys(i);a.length&&t(a).forEach(function(t){var e=i["#"+t.id],a=t.hasAttribute("data-a11y-toggle-open"),o=[];e.forEach(function(e){e.id||e.setAttribute("id","a11y-toggle-"+r++),e.setAttribute("aria-controls",t.id),e.setAttribute("aria-expanded",a),o.push(e.id)}),t.setAttribute("aria-hidden",!a),t.hasAttribute("aria-labelledby")||t.setAttribute("aria-labelledby",o.join(" ")),n[t.id]=t})};document.addEventListener("DOMContentLoaded",function(){o()}),document.addEventListener("click",function(t){var r=e(t.target);a(r)}),document.addEventListener("keyup",function(t){if(13===t.which||32===t.which){var r=e(t.target);r&&"button"===r.getAttribute("role")&&a(r)}}),window&&(window.a11yToggle=o)}(); -------------------------------------------------------------------------------- /assets/scss/bourbon/bourbon/utilities/_font-source-declaration.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Builds the `src` list for an `@font-face` declaration. 4 | /// 5 | /// @link https://goo.gl/Ru1bKP 6 | /// 7 | /// @argument {string} $font-family 8 | /// 9 | /// @argument {string} $file-path 10 | /// 11 | /// @argument {boolean} $asset-pipeline 12 | /// 13 | /// @argument {list} $file-formats 14 | /// 15 | /// @return {list} 16 | /// 17 | /// @require {function} _contains 18 | /// 19 | /// @access private 20 | 21 | @function _font-source-declaration( 22 | $font-family, 23 | $file-path, 24 | $asset-pipeline, 25 | $file-formats 26 | ) { 27 | $src: (); 28 | 29 | $formats-map: ( 30 | eot: "#{$file-path}.eot?#iefix" format("embedded-opentype"), 31 | woff2: "#{$file-path}.woff2" format("woff2"), 32 | woff: "#{$file-path}.woff" format("woff"), 33 | ttf: "#{$file-path}.ttf" format("truetype"), 34 | svg: "#{$file-path}.svg##{$font-family}" format("svg"), 35 | ); 36 | 37 | @each $key, $values in $formats-map { 38 | @if _contains($file-formats, $key) { 39 | $file-path: nth($values, 1); 40 | $font-format: nth($values, 2); 41 | 42 | @if $asset-pipeline == true { 43 | $src: append($src, font-url($file-path) $font-format, comma); 44 | } @else { 45 | $src: append($src, url($file-path) $font-format, comma); 46 | } 47 | } 48 | } 49 | 50 | @return $src; 51 | } 52 | -------------------------------------------------------------------------------- /lib/webbkoll_web/views/error_helpers.ex: -------------------------------------------------------------------------------- 1 | defmodule WebbkollWeb.ErrorHelpers do 2 | @moduledoc """ 3 | Conveniences for translating and building error messages. 4 | """ 5 | 6 | use Phoenix.HTML 7 | 8 | @doc """ 9 | Generates tag for inlined form input errors. 10 | """ 11 | def error_tag(form, field) do 12 | if error = form.errors[field] do 13 | content_tag(:span, translate_error(error), class: "help-block") 14 | end 15 | end 16 | 17 | @doc """ 18 | Translates an error message using gettext. 19 | """ 20 | def translate_error({msg, opts}) do 21 | # Because error messages were defined within Ecto, we must 22 | # call the Gettext module passing our Gettext backend. We 23 | # also use the "errors" domain as translations are placed 24 | # in the errors.po file. 25 | # Ecto will pass the :count keyword if the error message is 26 | # meant to be pluralized. 27 | # On your own code and templates, depending on whether you 28 | # need the message to be pluralized or not, this could be 29 | # written simply as: 30 | # 31 | # dngettext "errors", "1 file", "%{count} files", count 32 | # dgettext "errors", "is invalid" 33 | # 34 | if count = opts[:count] do 35 | Gettext.dngettext(WebbkollWeb.Gettext, "errors", msg, msg, count, opts) 36 | else 37 | Gettext.dgettext(WebbkollWeb.Gettext, "errors", msg, opts) 38 | end 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /assets/scss/base/_typography.scss: -------------------------------------------------------------------------------- 1 | html { 2 | color: $base-font-color; 3 | font-family: $base-font-family; 4 | font-size: 18px; 5 | line-height: $base-line-height; 6 | } 7 | 8 | @include media($mobile) { 9 | html { 10 | font-size: 16px; 11 | } 12 | } 13 | 14 | h1, 15 | h2, 16 | h3, 17 | h4, 18 | h5, 19 | h6 { 20 | font-family: $heading-font-family; 21 | font-size: modular-scale(1); 22 | font-weight: normal; 23 | line-height: $heading-line-height; 24 | margin: 0 0 $magic-number/2; 25 | } 26 | 27 | h1 { 28 | font-size: modular-scale(4); 29 | line-height: $magic-number*2; 30 | } 31 | 32 | h2 { 33 | font-size: modular-scale(3); 34 | line-height: $magic-number*2; 35 | } 36 | 37 | h3 { 38 | font-size: modular-scale(2); 39 | line-height: $magic-number*1.25; 40 | } 41 | 42 | h4 { 43 | font-size: modular-scale(1); 44 | } 45 | 46 | p { 47 | margin: 0 0 $magic-number/2; 48 | } 49 | 50 | p + h2, 51 | p + h3, 52 | p + h4 { 53 | margin-top: $magic-number; 54 | } 55 | 56 | a { 57 | color: $action-color; 58 | text-decoration-skip: ink; 59 | transition: color $base-duration $base-timing; 60 | 61 | &:hover { 62 | color: shade($action-color, 25%); 63 | } 64 | 65 | &:focus { 66 | outline: $focus-outline; 67 | outline-offset: $focus-outline-offset; 68 | } 69 | } 70 | 71 | hr { 72 | border-bottom: $base-border; 73 | border-left: 0; 74 | border-right: 0; 75 | border-top: 0; 76 | margin: $base-spacing 0; 77 | } -------------------------------------------------------------------------------- /assets/scss/neat/grid/_row.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Designates the element as a row of columns in the grid layout. It clears the floats on the element and sets its display property. Rows can't be nested, but there can be more than one row element—with different display properties—per layout. 4 | /// 5 | /// @param {String} $display [default] 6 | /// Sets the display property of the element and the display context that will be used by its children. Can be `block` or `table`. 7 | /// 8 | /// @param {String} $direction [$default-layout-direction] 9 | /// Sets the layout direction. Can be `LTR` (left-to-right) or `RTL` (right-to-left). 10 | /// 11 | /// @example scss - Usage 12 | /// .element { 13 | /// @include row(); 14 | /// } 15 | /// 16 | /// @example css - CSS Output 17 | /// .element { 18 | /// *zoom: 1; 19 | /// display: block; 20 | /// } 21 | /// 22 | /// .element:before, .element:after { 23 | /// content: " "; 24 | /// display: table; 25 | /// } 26 | /// 27 | /// .element:after { 28 | /// clear: both; 29 | /// } 30 | 31 | @mixin row($display: default, $direction: $default-layout-direction) { 32 | 33 | $layout-direction: $direction !global; 34 | 35 | @if $display == table { 36 | display: table; 37 | @include fill-parent; 38 | table-layout: fixed; 39 | $container-display-table: true !global; 40 | } @else { 41 | @include clearfix; 42 | display: block; 43 | $container-display-table: false !global; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /lib/webbkoll/sites/sites.ex: -------------------------------------------------------------------------------- 1 | defmodule Webbkoll.Sites do 2 | alias Webbkoll.Sites.Site 3 | 4 | def add_site(url) do 5 | id = Uniq.UUID.uuid4() 6 | 7 | site = %Site{ 8 | id: id, 9 | input_url: url, 10 | try_count: 0, 11 | status: "queue", 12 | inserted_at: System.system_time(:microsecond) 13 | } 14 | 15 | ConCache.put(:site_cache, id, site) 16 | 17 | {:ok, site} 18 | end 19 | 20 | def update_site(id, params) do 21 | ConCache.update(:site_cache, id, fn old -> 22 | { 23 | :ok, 24 | old |> Map.merge(params) |> Map.merge(%{updated_at: System.system_time(:microsecond)}) 25 | } 26 | end) 27 | end 28 | 29 | def increment_site_tries(id) do 30 | ConCache.update(:site_cache, id, fn old -> 31 | {:ok, Map.update(old, :try_count, 0, &(&1 + 1))} 32 | end) 33 | end 34 | 35 | def get_site(id) do 36 | ConCache.get(:site_cache, id) 37 | end 38 | 39 | def get_latest_from_cache(url) do 40 | input = get_sites_by(%{input_url: url}) 41 | 42 | input 43 | |> Enum.filter(&is_tuple/1) 44 | |> Enum.sort(fn x, y -> 45 | elem(x, 1) 46 | |> Map.get(:inserted_at) > 47 | elem(y, 1) 48 | |> Map.get(:inserted_at) 49 | end) 50 | |> List.first() 51 | end 52 | 53 | def get_sites_by(params) do 54 | :ets.match_object(ConCache.ets(:site_cache), {:_, params}) 55 | end 56 | 57 | def is_valid_id?(id) do 58 | Uniq.UUID.info(id) 59 | end 60 | end 61 | -------------------------------------------------------------------------------- /lib/webbkoll_web/endpoint.ex: -------------------------------------------------------------------------------- 1 | defmodule WebbkollWeb.Endpoint do 2 | use Phoenix.Endpoint, otp_app: :webbkoll 3 | 4 | # socket "/socket", WebbkollWeb.UserSocket, 5 | # websocket: true, # or list of options 6 | # longpoll: false 7 | 8 | plug RemoteIp 9 | 10 | # Serve at "/" the static files from "priv/static" directory. 11 | # 12 | # You should set gzip to true if you are running phoenix.digest 13 | # when deploying your static files in production. 14 | plug( 15 | Plug.Static, 16 | at: "/", 17 | from: :webbkoll, 18 | gzip: false, 19 | only: ~w(css fonts images js favicon.ico robots.txt .well-known) 20 | ) 21 | 22 | # Code reloading can be explicitly enabled under the 23 | # :code_reloader configuration of your endpoint. 24 | if code_reloading? do 25 | socket("/phoenix/live_reload/socket", Phoenix.LiveReloader.Socket) 26 | plug(Phoenix.LiveReloader) 27 | plug(Phoenix.CodeReloader) 28 | end 29 | 30 | plug Phoenix.LiveDashboard.RequestLogger, 31 | param_key: "request_logger" 32 | #cookie_key: "request_logger" 33 | plug(Plug.RequestId) 34 | plug(Plug.Logger) 35 | 36 | plug( 37 | Plug.Parsers, 38 | parsers: [:urlencoded, :multipart, :json], 39 | pass: ["*/*"], 40 | json_decoder: Phoenix.json_library() 41 | ) 42 | 43 | plug(Plug.MethodOverride) 44 | plug(Plug.Head) 45 | 46 | plug(Plug.Session, store: :cookie, key: "_webbkoll_key", signing_salt: "4ZOjrKOO") 47 | 48 | plug(WebbkollWeb.Router) 49 | 50 | socket "/live", Phoenix.LiveView.Socket 51 | end 52 | -------------------------------------------------------------------------------- /assets/scss/_compatibility.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | //// 4 | /// @type list 5 | /// 6 | /// @link goo.gl/Cxb26i 7 | //// 8 | 9 | $font-stack-helvetica: ( 10 | "Helvetica Neue", 11 | "Helvetica", 12 | "Arial", 13 | sans-serif, 14 | ); 15 | 16 | $font-stack-lucida-grande: ( 17 | "Lucida Grande", 18 | "Lucida Sans Unicode", 19 | "Geneva", 20 | "Verdana", 21 | sans-serif, 22 | ); 23 | 24 | $font-stack-verdana: ( 25 | "Verdana", 26 | "Geneva", 27 | sans-serif, 28 | ); 29 | 30 | $font-stack-system: ( 31 | -apple-system, 32 | BlinkMacSystemFont, 33 | "Segoe UI", 34 | "Roboto", 35 | "Oxygen", 36 | "Ubuntu", 37 | "Cantarell", 38 | "Fira Sans", 39 | "Droid Sans", 40 | "Helvetica Neue", 41 | sans-serif, 42 | ); 43 | 44 | $font-stack-garamond: ( 45 | "Garamond", 46 | "Baskerville", 47 | "Baskerville Old Face", 48 | "Hoefler Text", 49 | "Times New Roman", 50 | serif, 51 | ); 52 | 53 | $font-stack-georgia: ( 54 | "Georgia", 55 | "Times", 56 | "Times New Roman", 57 | serif, 58 | ); 59 | 60 | $font-stack-hoefler-text: ( 61 | "Hoefler Text", 62 | "Baskerville Old Face", 63 | "Garamond", 64 | "Times New Roman", 65 | serif, 66 | ); 67 | 68 | $font-stack-consolas: ( 69 | "Consolas", 70 | "monaco", 71 | monospace, 72 | ); 73 | 74 | $font-stack-courier-new: ( 75 | "Courier New", 76 | "Courier", 77 | "Lucida Sans Typewriter", 78 | "Lucida Typewriter", 79 | monospace, 80 | ); 81 | 82 | $font-stack-monaco: ( 83 | "monaco", 84 | "Consolas", 85 | "Lucida Console", 86 | monospace, 87 | ); -------------------------------------------------------------------------------- /assets/scss/bourbon/bourbon/library/_position.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Provides a concise, one-line method for setting an element’s positioning 4 | /// properties: `position`, `top`, `right`, `bottom` and `left`. Use a `null` 5 | /// value to “skip” an edge of the box. 6 | /// 7 | /// @argument {string} $position 8 | /// A CSS position value. 9 | /// 10 | /// @argument {list} $box-edge-values 11 | /// List of lengths; accepts CSS shorthand. 12 | /// 13 | /// @example scss 14 | /// .element { 15 | /// @include position(relative, 0 null null 10em); 16 | /// } 17 | /// 18 | /// // CSS Output 19 | /// .element { 20 | /// left: 10em; 21 | /// position: relative; 22 | /// top: 0; 23 | /// } 24 | /// 25 | /// @example scss 26 | /// .element { 27 | /// @include position(absolute, 0); 28 | /// } 29 | /// 30 | /// // CSS Output 31 | /// .element { 32 | /// position: absolute; 33 | /// top: 0; 34 | /// right: 0; 35 | /// bottom: 0; 36 | /// left: 0; 37 | /// } 38 | /// 39 | /// @require {function} _is-length 40 | /// 41 | /// @require {function} _unpack-shorthand 42 | 43 | @mixin position( 44 | $position, 45 | $box-edge-values 46 | ) { 47 | $box-edge-values: _unpack-shorthand($box-edge-values); 48 | $offsets: ( 49 | top: nth($box-edge-values, 1), 50 | right: nth($box-edge-values, 2), 51 | bottom: nth($box-edge-values, 3), 52 | left: nth($box-edge-values, 4), 53 | ); 54 | 55 | position: $position; 56 | 57 | @each $offset, $value in $offsets { 58 | @if _is-length($value) { 59 | #{$offset}: $value; 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /test/fixtures/referrer_header.json: -------------------------------------------------------------------------------- 1 | { 2 | "success": true, 3 | "input_url": "http://www.example.com/", 4 | "final_url": "http://www.example.com/", 5 | "request_headers": {}, 6 | "response_headers": { 7 | "date": "Wed, 24 Aug 2016 13:37:15 GMT", 8 | "server": "Apache", 9 | "x-content-type-options": "nosniff", 10 | "last-modified": "Wed, 24 Aug 2016 13:35:23 GMT", 11 | "etag": "\"42-53ad15a724042\"", 12 | "accept-ranges": "bytes", 13 | "content-length": "66", 14 | "cache-control": "max-age=1209600", 15 | "expires": "Wed, 07 Sep 2016 13:37:15 GMT", 16 | "referrer-policy": "no-referrer", 17 | "keep-alive": "timeout=5, max=100", 18 | "connection": "Keep-Alive", 19 | "content-type": "text/html; charset=UTF-8" 20 | }, 21 | "requests": [ 22 | { 23 | "headers": [ 24 | { 25 | "name": "Accept", 26 | "value": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" 27 | }, 28 | { 29 | "name": "User-Agent", 30 | "value": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.116 Safari/537.36" 31 | } 32 | ], 33 | "id": 1, 34 | "method": "GET", 35 | "time": "2016-08-24T13:37:15.088Z", 36 | "url": "http://www.example.com/" 37 | } 38 | ], 39 | "cookies": [], 40 | "had_js_errors": false, 41 | "content": "\n \n \n\n" 42 | } 43 | -------------------------------------------------------------------------------- /lib/webbkoll_web/templates/page/donate.html.heex: -------------------------------------------------------------------------------- 1 |
2 |

<%= gettext "Donate" %>

3 | 4 |

<%= gettext(~s|Webbkoll is a project by Dataskydd.net Sverige, a Swedish non-governmental organization (organization number 802495-4797) working on making data protection easy in law and in practice. We are not affiliated with any political party.|) |> raw %>

5 | 6 |

<%= gettext "We operate on a very small budget, and servers are usually our main expense; most work is done in our free time. Every euro (or krona) counts!" %>

7 | 8 |

<%= gettext("If you would like to make a contribution to the general funds of Dataskydd.net (helping both Webbkoll as well as our other activities), you can transfer money to the following bank account:") |> raw() %>

9 | 10 |
    11 |
  • Bank: SEB (Skandinaviska Enskilda Banken)
  • 12 |
  • BIC/SWIFT: ESSESESS
  • 13 |
  • IBAN: SE2150000000052031057715
  • 14 |
15 | 16 |

<%= gettext "Please write \"Donation\" in the message field. Any amount is much appreciated! (From a Swedish bank account, the number would be 52031057715.)" %>

17 | 18 |

<%= gettext "Our address (if necessary):" %>

19 | 20 |

21 | Dataskydd.net Sverige
22 | c/o Jensen-Urstad
23 | Bondegatan 64
24 | 11633 Stockholm
25 | Sweden 26 |

27 | 28 |

<%= gettext "Our bank's address (if necessary):" %>

29 |

30 | SEB
31 | 106 40 Stockholm
32 | Sweden 33 |

34 | 35 |

<%= gettext "At the moment we cannot accept Bitcoin or any other cryptocurrency." %>

36 |
-------------------------------------------------------------------------------- /test/fixtures/csp_referrer.json: -------------------------------------------------------------------------------- 1 | { 2 | "success": true, 3 | "input_url": "http://www.example.com/", 4 | "final_url": "http://www.example.com/", 5 | "request_headers": {}, 6 | "response_headers": { 7 | "date": "Wed, 24 Aug 2016 13:37:15 GMT", 8 | "server": "Apache", 9 | "x-content-type-options": "nosniff", 10 | "last-modified": "Wed, 24 Aug 2016 13:35:23 GMT", 11 | "etag": "\"42-53ad15a724042\"", 12 | "accept-ranges": "bytes", 13 | "content-length": "66", 14 | "cache-control": "max-age=1209600", 15 | "expires": "Wed, 07 Sep 2016 13:37:15 GMT", 16 | "content-security-policy": "referrer no-referrer", 17 | "keep-alive": "timeout=5, max=100", 18 | "connection": "Keep-Alive", 19 | "content-type": "text/html; charset=UTF-8" 20 | }, 21 | "requests": [ 22 | { 23 | "headers": [ 24 | { 25 | "name": "Accept", 26 | "value": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" 27 | }, 28 | { 29 | "name": "User-Agent", 30 | "value": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.116 Safari/537.36" 31 | } 32 | ], 33 | "id": 1, 34 | "method": "GET", 35 | "time": "2016-08-24T13:37:15.088Z", 36 | "url": "http://www.example.com/" 37 | } 38 | ], 39 | "cookies": [], 40 | "had_js_errors": false, 41 | "content": "\n \n \n\n" 42 | } 43 | -------------------------------------------------------------------------------- /test/fixtures/header_csp.json: -------------------------------------------------------------------------------- 1 | { 2 | "success": true, 3 | "input_url": "http://www.example.com/", 4 | "final_url": "http://www.example.com/", 5 | "request_headers": {}, 6 | "response_headers": { 7 | "date": "Wed, 24 Aug 2016 13:50:07 GMT", 8 | "server": "Apache", 9 | "x-content-type-options": "nosniff", 10 | "last-modified": "Wed, 24 Aug 2016 13:49:28 GMT", 11 | "etag": "\"73-53ad18cca82af\"", 12 | "accept-ranges": "bytes", 13 | "content-length": "115", 14 | "cache-control": "max-age=1209600", 15 | "expires": "Wed, 07 Sep 2016 13:50:07 GMT", 16 | "content-security-policy": "default-src 'self'", 17 | "keep-alive": "timeout=5, max=100", 18 | "connection": "Keep-Alive", 19 | "content-type": "text/html; charset=UTF-8" 20 | }, 21 | "requests": [ 22 | { 23 | "headers": [ 24 | { 25 | "name": "Accept", 26 | "value": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" 27 | }, 28 | { 29 | "name": "User-Agent", 30 | "value": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.116 Safari/537.36" 31 | } 32 | ], 33 | "id": 1, 34 | "method": "GET", 35 | "time": "2016-08-24T13:50:07.723Z", 36 | "url": "http://www.example.com/" 37 | } 38 | ], 39 | "cookies": [], 40 | "had_js_errors": false, 41 | "content": "\n \n \n\n" 42 | } 43 | -------------------------------------------------------------------------------- /lib/webbkoll_web/router.ex: -------------------------------------------------------------------------------- 1 | defmodule WebbkollWeb.Router do 2 | use WebbkollWeb, :router 3 | 4 | @default_locale Application.compile_env(:webbkoll, :default_locale) 5 | 6 | pipeline :browser do 7 | plug(:accepts, ["html"]) 8 | plug(:fetch_session) 9 | plug(:fetch_flash) 10 | plug(:protect_from_forgery) 11 | plug(:put_secure_browser_headers) 12 | end 13 | 14 | pipeline :webbkoll do 15 | plug(WebbkollWeb.Plugs.MoreSecureHeaders) 16 | plug(WebbkollWeb.Plugs.Locale, @default_locale) 17 | end 18 | 19 | pipeline :api do 20 | plug(:accepts, ["json", "html"]) 21 | end 22 | 23 | if Mix.env() == :dev do 24 | import Phoenix.LiveDashboard.Router 25 | 26 | scope "/api", WebbkollWeb do 27 | pipe_through(:api) 28 | 29 | post("/check", API.SiteController, :create) 30 | get("/check", API.SiteController, :show) 31 | end 32 | 33 | scope "/" do 34 | pipe_through :browser 35 | live_dashboard "/dashboard" 36 | end 37 | end 38 | 39 | scope "/", WebbkollWeb do 40 | pipe_through([:browser, :webbkoll]) 41 | 42 | get("/", PageController, :index) 43 | end 44 | 45 | scope "/:locale", WebbkollWeb do 46 | pipe_through([:browser, :webbkoll]) 47 | 48 | post("/check", SiteController, :create) 49 | get("/check", SiteController, :redirect_to_index) 50 | get("/status", SiteController, :status) 51 | get("/results", SiteController, :results) 52 | 53 | get("/news", PageController, :news) 54 | get("/faq", PageController, :faq) 55 | get("/about", PageController, :about) 56 | get("/donate", PageController, :donate) 57 | 58 | get("/", PageController, :index) 59 | end 60 | end 61 | -------------------------------------------------------------------------------- /test/fixtures/meta_csp.json: -------------------------------------------------------------------------------- 1 | { 2 | "success": true, 3 | "input_url": "http://www.example.com/", 4 | "final_url": "http://www.example.com/", 5 | "request_headers": {}, 6 | "response_headers": { 7 | "date": "Wed, 24 Aug 2016 13:50:07 GMT", 8 | "server": "Apache", 9 | "x-content-type-options": "nosniff", 10 | "last-modified": "Wed, 24 Aug 2016 13:49:28 GMT", 11 | "etag": "\"73-53ad18cca82af\"", 12 | "accept-ranges": "bytes", 13 | "content-length": "115", 14 | "cache-control": "max-age=1209600", 15 | "expires": "Wed, 07 Sep 2016 13:50:07 GMT", 16 | "keep-alive": "timeout=5, max=100", 17 | "connection": "Keep-Alive", 18 | "content-type": "text/html; charset=UTF-8" 19 | }, 20 | "requests": [ 21 | { 22 | "headers": [ 23 | { 24 | "name": "Accept", 25 | "value": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" 26 | }, 27 | { 28 | "name": "User-Agent", 29 | "value": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.116 Safari/537.36" 30 | } 31 | ], 32 | "id": 1, 33 | "method": "GET", 34 | "time": "2016-08-24T13:50:07.723Z", 35 | "url": "http://www.example.com/" 36 | } 37 | ], 38 | "cookies": [], 39 | "had_js_errors": false, 40 | "content": "\n \n \n \n\n" 41 | } 42 | -------------------------------------------------------------------------------- /test/fixtures/csp_and_referrer_header.json: -------------------------------------------------------------------------------- 1 | { 2 | "success": true, 3 | "input_url": "http://www.example.com/", 4 | "final_url": "http://www.example.com/", 5 | "request_headers": {}, 6 | "response_headers": { 7 | "date": "Wed, 24 Aug 2016 13:37:15 GMT", 8 | "server": "Apache", 9 | "x-content-type-options": "nosniff", 10 | "last-modified": "Wed, 24 Aug 2016 13:35:23 GMT", 11 | "etag": "\"42-53ad15a724042\"", 12 | "accept-ranges": "bytes", 13 | "content-length": "66", 14 | "cache-control": "max-age=1209600", 15 | "expires": "Wed, 07 Sep 2016 13:37:15 GMT", 16 | "content-security-policy": "referrer unsafe-url", 17 | "referrer-policy": "no-referrer", 18 | "keep-alive": "timeout=5, max=100", 19 | "connection": "Keep-Alive", 20 | "content-type": "text/html; charset=UTF-8" 21 | }, 22 | "requests": [ 23 | { 24 | "headers": [ 25 | { 26 | "name": "Accept", 27 | "value": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" 28 | }, 29 | { 30 | "name": "User-Agent", 31 | "value": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.116 Safari/537.36" 32 | } 33 | ], 34 | "id": 1, 35 | "method": "GET", 36 | "time": "2016-08-24T13:37:15.088Z", 37 | "url": "http://www.example.com/" 38 | } 39 | ], 40 | "cookies": [], 41 | "had_js_errors": false, 42 | "content": "\n \n \n\n" 43 | } 44 | -------------------------------------------------------------------------------- /lib/webbkoll_web.ex: -------------------------------------------------------------------------------- 1 | defmodule WebbkollWeb do 2 | @moduledoc """ 3 | A module that keeps using definitions for controllers, 4 | views and so on. 5 | 6 | This can be used in your application as: 7 | 8 | use WebbkollWeb, :controller 9 | use WebbkollWeb, :view 10 | 11 | The definitions below will be executed for every view, 12 | controller, etc, so keep them short and clean, focused 13 | on imports, uses and aliases. 14 | 15 | Do NOT define functions inside the quoted expressions 16 | below. 17 | """ 18 | 19 | def controller do 20 | quote do 21 | use Phoenix.Controller, namespace: WebbkollWeb 22 | 23 | alias WebbkollWeb.Router.Helpers, as: Routes 24 | import WebbkollWeb.Gettext 25 | import Webbkoll.Helpers 26 | end 27 | end 28 | 29 | def view do 30 | quote do 31 | use Phoenix.View, root: "lib/webbkoll_web/templates", namespace: WebbkollWeb 32 | 33 | # Import convenience functions from controllers 34 | import Phoenix.Controller, only: [get_csrf_token: 0, get_flash: 2, view_module: 1] 35 | import Phoenix.LiveView.Helpers 36 | import Phoenix.Component 37 | 38 | # Use all HTML functionality (forms, tags, etc) 39 | use Phoenix.HTML 40 | 41 | alias WebbkollWeb.Router.Helpers, as: Routes 42 | import WebbkollWeb.ErrorHelpers 43 | import WebbkollWeb.Gettext 44 | import Webbkoll.Helpers 45 | end 46 | end 47 | 48 | def router do 49 | quote do 50 | use Phoenix.Router 51 | end 52 | end 53 | 54 | @doc """ 55 | When used, dispatch to the appropriate controller/view/etc. 56 | """ 57 | defmacro __using__(which) when is_atom(which) do 58 | apply(__MODULE__, which, []) 59 | end 60 | end 61 | -------------------------------------------------------------------------------- /test/fixtures/csp_and_meta_referrer.json: -------------------------------------------------------------------------------- 1 | { 2 | "success": true, 3 | "input_url": "http://www.example.com/", 4 | "final_url": "http://www.example.com/", 5 | "request_headers": {}, 6 | "response_headers": { 7 | "date": "Wed, 24 Aug 2016 13:50:07 GMT", 8 | "server": "Apache", 9 | "x-content-type-options": "nosniff", 10 | "last-modified": "Wed, 24 Aug 2016 13:49:28 GMT", 11 | "etag": "\"73-53ad18cca82af\"", 12 | "accept-ranges": "bytes", 13 | "content-length": "115", 14 | "cache-control": "max-age=1209600", 15 | "expires": "Wed, 07 Sep 2016 13:50:07 GMT", 16 | "content-security-policy": "referrer unsafe-url", 17 | "keep-alive": "timeout=5, max=100", 18 | "connection": "Keep-Alive", 19 | "content-type": "text/html; charset=UTF-8" 20 | }, 21 | "requests": [ 22 | { 23 | "headers": [ 24 | { 25 | "name": "Accept", 26 | "value": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" 27 | }, 28 | { 29 | "name": "User-Agent", 30 | "value": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.116 Safari/537.36" 31 | } 32 | ], 33 | "id": 1, 34 | "method": "GET", 35 | "time": "2016-08-24T13:50:07.723Z", 36 | "url": "http://www.example.com/" 37 | } 38 | ], 39 | "cookies": [], 40 | "had_js_errors": false, 41 | "content": "\n \n \n \n\n" 42 | } 43 | -------------------------------------------------------------------------------- /lib/webbkoll_web/templates/site/_cookie_table.html.heex: -------------------------------------------------------------------------------- 1 |
2 |

<%= @label %> (<%= @amount %>)

3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | <%= for cookie <- @cookies do %> 17 | 18 | 19 | 20 | 21 | 24 | 25 | 26 | 34 | 35 | <% end %> 36 | 37 |
<%= gettext "Domain" %><%= gettext "Name" %><%= gettext "Value" %><%= gettext "Expires on" %>HttpOnlySecureSameSite
<%= cookie["domain"] %><%= truncate(cookie["name"], 20) %><%= truncate(cookie["value"], 20) %> 22 | <%= if cookie["session"] == true, do: "session", else: format_timestamp(cookie["expires"]) %> 23 | <%= if cookie["httpOnly"], do: icon(:pass), else: icon(:fail) %><%= if cookie["secure"], do: icon(:pass), else: icon(:fail) %> 27 | <%= if cookie["sameSite"] do %> 28 | <%= icon(:pass) %> 29 | (<%= cookie["sameSite"] %>) 30 | <% else %> 31 | <%= icon(:fail) %> 32 | <% end %> 33 |
38 |
-------------------------------------------------------------------------------- /test/fixtures/header_csp_and_meta_csp.json: -------------------------------------------------------------------------------- 1 | { 2 | "success": true, 3 | "input_url": "http://www.example.com/", 4 | "final_url": "http://www.example.com/", 5 | "request_headers": {}, 6 | "response_headers": { 7 | "date": "Wed, 24 Aug 2016 13:50:07 GMT", 8 | "server": "Apache", 9 | "x-content-type-options": "nosniff", 10 | "last-modified": "Wed, 24 Aug 2016 13:49:28 GMT", 11 | "etag": "\"73-53ad18cca82af\"", 12 | "accept-ranges": "bytes", 13 | "content-length": "115", 14 | "cache-control": "max-age=1209600", 15 | "expires": "Wed, 07 Sep 2016 13:50:07 GMT", 16 | "content-security-policy": "default-src 'self'", 17 | "keep-alive": "timeout=5, max=100", 18 | "connection": "Keep-Alive", 19 | "content-type": "text/html; charset=UTF-8" 20 | }, 21 | "requests": [ 22 | { 23 | "headers": [ 24 | { 25 | "name": "Accept", 26 | "value": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" 27 | }, 28 | { 29 | "name": "User-Agent", 30 | "value": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.116 Safari/537.36" 31 | } 32 | ], 33 | "id": 1, 34 | "method": "GET", 35 | "time": "2016-08-24T13:50:07.723Z", 36 | "url": "http://www.example.com/" 37 | } 38 | ], 39 | "cookies": [], 40 | "had_js_errors": false, 41 | "content": "\n \n \n \n\n" 42 | } 43 | -------------------------------------------------------------------------------- /assets/scss/neat/grid/_shift.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Translates an element horizontally by a number of columns. Positive arguments shift the element to the active layout direction, while negative ones shift it to the opposite direction. 4 | /// 5 | /// @param {Number (unitless)} $n-columns [1] 6 | /// Number of columns by which the element shifts. 7 | /// 8 | /// @example scss - Usage 9 | /// .element { 10 | /// @include shift(-3); 11 | /// } 12 | /// 13 | /// @example css - CSS output 14 | /// .element { 15 | /// margin-left: -25.58941%; 16 | /// } 17 | 18 | @mixin shift($n-columns: 1) { 19 | @include shift-in-context($n-columns); 20 | } 21 | 22 | /// Translates an element horizontally by a number of columns, in a specific nesting context. 23 | /// 24 | /// @param {List} $shift 25 | /// A list containing the number of columns to shift (`$columns`) and the number of columns of the parent element (`$container-columns`). 26 | /// 27 | /// The two values can be separated with any string such as `of`, `/`, etc. 28 | /// 29 | /// @example scss - Usage 30 | /// .element { 31 | /// @include shift(-3 of 6); 32 | /// } 33 | /// 34 | /// @example css - CSS output 35 | /// .element { 36 | /// margin-left: -52.41458%; 37 | /// } 38 | 39 | @mixin shift-in-context($shift: $columns of $container-columns) { 40 | $n-columns: nth($shift, 1); 41 | $parent-columns: container-shift($shift) !global; 42 | 43 | $direction: get-direction($layout-direction, $default-layout-direction); 44 | $opposite-direction: get-opposite-direction($direction); 45 | 46 | margin-#{$opposite-direction}: $n-columns * flex-grid(1, $parent-columns) + $n-columns * flex-gutter($parent-columns); 47 | 48 | // Reset nesting context 49 | $parent-columns: $grid-columns !global; 50 | } 51 | -------------------------------------------------------------------------------- /lib/webbkoll_web/templates/site/_hsts_host.html.heex: -------------------------------------------------------------------------------- 1 |

2 | <%= gettext(~s|HSTS policy for https://%{host}:|, host: @host) %>
3 | <%= safe_to_string(html_escape(@hsts.data)) %> 4 |

5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 22 | 25 | 26 | 27 | 34 | 37 | 38 | 39 | 50 | 56 | 57 | 58 |
<%= gettext "Pass" %><%= gettext "Test" %>
16 | <%= if @hsts.pass do %> 17 | <%= icon(:pass) %> 18 | <% else %> 19 | <%= icon(:fail) %> 20 | <% end %> 21 | 23 | <%= gettext(~s|max-age set to at least 6 months|) |> raw() %> 24 |
28 | <%= if @hsts.includesubdomains do %> 29 | <%= icon(:pass) %> 30 | <% else %> 31 | <%= icon(:fail) %> 32 | <% end %> 33 | 35 | <%= gettext(~s|includeSubDomains — policy also applies to subdomains|) |> raw() %> 36 |
40 | <%= if @is_base do %> 41 | <%= if @hsts.preload do %> 42 | <%= icon(:pass) %> 43 | <% else %> 44 | <%= icon(:fail) %> 45 | <% end %> 46 | <% else %> 47 | <%= icon(:optional) %> 48 | <% end %> 49 | 51 | <%= gettext(~s|preload — requests inclusion in preload lists|) |> raw() %> 52 | <%= if not @is_base do %> 53 | <%= gettext("[only relevant for base domain]") %> 54 | <% end %> 55 |
59 | -------------------------------------------------------------------------------- /assets/scss/.sass-cache/72dda0c11013fc7994d6c543544dc280a238d0cf/_backface-visibility.scssc: -------------------------------------------------------------------------------- 1 | 3.4.21 (Selective Steve) 2 | 7587d5653fa2b48af9371d2b63a2a666ac6ac928 3 | o:Sass::Tree::RootNode :@children[o:Sass::Tree::MixinDefNode : 4 | @nameI"backface-visibility:ET: 5 | @args[[o:!Sass::Script::Tree::Variable ;I"visibility; T:@underscored_nameI"visibility; T: 6 | @linei:@source_rangeo:Sass::Source::Range :@start_poso:Sass::Source::Position; i: @offseti!: @end_poso;; i;i,: 7 | @fileI"+bourbon/css3/_backface-visibility.scss; T:@importero: Sass::Importers::Filesystem: 8 | @rootI"A/home/andersju/jobb/dataskydd/syzygy/bourbontest/stylesheets; T:@real_rootI"A/home/andersju/jobb/dataskydd/syzygy/bourbontest/stylesheets; T:@same_name_warningso:Set: 9 | @hash}F:@filename@: @options{0: @splat0;[o:Sass::Tree::MixinNode;I" prefixer; T; 10 | [o: Sass::Script::Tree::Literal : @valueo: Sass::Script::Value::String ;!I"backface-visibility; T: 11 | @type:identifier:"@deprecated_interp_equivalent0;@; i;o; ;o;; i;i;o;; i;i-;@;@;@o; ;I"visibility; T; I"visibility; T; i;o; ;o;; i;i/;o;; i;i:;@;@;@;@o:$Sass::Script::Tree::ListLiteral :@elements[o; ;!o;" ;!I" webkit; T;#;$;%0;@; i;o; ;o;; i;i<;o;; i;iB;@;@;@o; ;!o;" ;!I" spec; T;#;$;%0;@; i;o; ;o;; i;iC;o;; i;iG;@;@;@:@separator: 12 | space; i;o; ;o;; i;i;;o;; i;iG;@;@;@;@:@keywordso:Sass::Util::NormalizedMap:@key_strings{: @map{;0:@kwarg_splat0;[; i;o; ;o;; i;i;o;; i;iH;@;@;@; i;o; ;o;; i;i;o;; i;i.;@;@:@has_childrenT;@:@templateI"u@mixin backface-visibility($visibility) { 13 | @include prefixer(backface-visibility, $visibility, webkit spec); 14 | } 15 | ; T; i;o; ;o;; i;i;o;; i;i;@;@;/T;@ -------------------------------------------------------------------------------- /lib/webbkoll_web/controllers/page_controller.ex: -------------------------------------------------------------------------------- 1 | defmodule WebbkollWeb.PageController do 2 | use WebbkollWeb, :controller 3 | 4 | @check_host_only Application.compile_env(:webbkoll, :check_host_only) 5 | 6 | def index(conn, _params) do 7 | render( 8 | conn, 9 | "index.html", 10 | locale: conn.assigns.locale, 11 | page_title: gettext("Analyze"), 12 | page_description: 13 | gettext( 14 | "This tool helps you check what data-protecting measures a site has taken to help you exercise control over your privacy." 15 | ), 16 | check_host_only: @check_host_only 17 | ) 18 | end 19 | 20 | def news(conn, _params) do 21 | render( 22 | conn, 23 | "news.html", 24 | locale: conn.assigns.locale, 25 | page_title: gettext("News"), 26 | page_description: gettext("Recent changes on Webbkoll.") 27 | ) 28 | end 29 | 30 | def faq(conn, _params) do 31 | render( 32 | conn, 33 | "faq.html", 34 | locale: conn.assigns.locale, 35 | page_title: gettext("FAQ"), 36 | page_description: 37 | gettext( 38 | "The what and why of data protection and the principles of the EU general data protection regulation." 39 | ) 40 | ) 41 | end 42 | 43 | def about(conn, _params) do 44 | render( 45 | conn, 46 | "about.html", 47 | locale: conn.assigns.locale, 48 | page_title: gettext("About"), 49 | page_description: gettext("How Webbkoll works, who made it, and alternative services.") 50 | ) 51 | end 52 | 53 | def donate(conn, _params) do 54 | render( 55 | conn, 56 | "donate.html", 57 | locale: conn.assigns.locale, 58 | page_title: gettext("Donate"), 59 | page_description: gettext("How you can support our work.") 60 | ) 61 | end 62 | end 63 | -------------------------------------------------------------------------------- /assets/scss/bourbon/bourbon/library/_timing-functions.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | // scss-lint:disable SpaceAfterComma, UnnecessaryMantissa, TrailingZero 4 | 5 | //// 6 | /// CSS cubic-bezier timing functions. 7 | /// 8 | /// @link https://goo.gl/p8u6SK 9 | /// 10 | /// @type string 11 | //// 12 | 13 | $ease-in-quad: cubic-bezier(0.550, 0.085, 0.680, 0.530); 14 | $ease-in-cubic: cubic-bezier(0.550, 0.055, 0.675, 0.190); 15 | $ease-in-quart: cubic-bezier(0.895, 0.030, 0.685, 0.220); 16 | $ease-in-quint: cubic-bezier(0.755, 0.050, 0.855, 0.060); 17 | $ease-in-sine: cubic-bezier(0.470, 0.000, 0.745, 0.715); 18 | $ease-in-expo: cubic-bezier(0.950, 0.050, 0.795, 0.035); 19 | $ease-in-circ: cubic-bezier(0.600, 0.040, 0.980, 0.335); 20 | $ease-in-back: cubic-bezier(0.600, -0.280, 0.735, 0.045); 21 | 22 | $ease-out-quad: cubic-bezier(0.250, 0.460, 0.450, 0.940); 23 | $ease-out-cubic: cubic-bezier(0.215, 0.610, 0.355, 1.000); 24 | $ease-out-quart: cubic-bezier(0.165, 0.840, 0.440, 1.000); 25 | $ease-out-quint: cubic-bezier(0.230, 1.000, 0.320, 1.000); 26 | $ease-out-sine: cubic-bezier(0.390, 0.575, 0.565, 1.000); 27 | $ease-out-expo: cubic-bezier(0.190, 1.000, 0.220, 1.000); 28 | $ease-out-circ: cubic-bezier(0.075, 0.820, 0.165, 1.000); 29 | $ease-out-back: cubic-bezier(0.175, 0.885, 0.320, 1.275); 30 | 31 | $ease-in-out-quad: cubic-bezier(0.455, 0.030, 0.515, 0.955); 32 | $ease-in-out-cubic: cubic-bezier(0.645, 0.045, 0.355, 1.000); 33 | $ease-in-out-quart: cubic-bezier(0.770, 0.000, 0.175, 1.000); 34 | $ease-in-out-quint: cubic-bezier(0.860, 0.000, 0.070, 1.000); 35 | $ease-in-out-sine: cubic-bezier(0.445, 0.050, 0.550, 0.950); 36 | $ease-in-out-expo: cubic-bezier(1.000, 0.000, 0.000, 1.000); 37 | $ease-in-out-circ: cubic-bezier(0.785, 0.135, 0.150, 0.860); 38 | $ease-in-out-back: cubic-bezier(0.680, -0.550, 0.265, 1.550); 39 | -------------------------------------------------------------------------------- /lib/webbkoll/application.ex: -------------------------------------------------------------------------------- 1 | defmodule Webbkoll.Application do 2 | use Application 3 | 4 | @max_attempts Application.compile_env(:webbkoll, :max_attempts) 5 | @backends Application.compile_env(:webbkoll, :backends) 6 | 7 | # See http://elixir-lang.org/docs/stable/elixir/Application.html 8 | # for more information on OTP Applications 9 | def start(_type, _args) do 10 | children = [ 11 | # Start the PubSub system 12 | {Phoenix.PubSub, name: Webbkoll.PubSub}, 13 | # Start the endpoint when the application starts 14 | WebbkollWeb.Endpoint, 15 | # Add the Quantum supervisor 16 | Webbkoll.Scheduler, 17 | # Add the ConCache ETS key/value store 18 | {ConCache, 19 | [ 20 | name: :site_cache, 21 | ttl_check_interval: :timer.seconds(60), 22 | global_ttl: :timer.seconds(86_400) 23 | ]}, 24 | ] 25 | 26 | # See http://elixir-lang.org/docs/stable/elixir/Supervisor.html 27 | # for other strategies and supported options 28 | opts = [strategy: :one_for_one, name: Webbkoll.Supervisor] 29 | {:ok, supervisor} = Supervisor.start_link(children, opts) 30 | 31 | # Start job queue and workers 32 | Enum.each(@backends, fn {queue, settings} -> 33 | :ok = 34 | Honeydew.start_queue(queue, 35 | queue: Honeydew.Queue.ErlangQueue, 36 | failure_mode: { 37 | Honeydew.FailureMode.Retry, 38 | [times: @max_attempts - 1, base: 2] 39 | } 40 | ) 41 | 42 | :ok = Honeydew.start_workers(queue, Webbkoll.Worker, num: settings.concurrency) 43 | end) 44 | 45 | {:ok, supervisor} 46 | end 47 | 48 | # Tell Phoenix to update the endpoint configuration 49 | # whenever the application is updated. 50 | def config_change(changed, _new, removed) do 51 | WebbkollWeb.Endpoint.config_change(changed, removed) 52 | :ok 53 | end 54 | end 55 | -------------------------------------------------------------------------------- /mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Webbkoll.Mixfile do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :webbkoll, 7 | version: "0.0.1", 8 | elixir: "~> 1.7", 9 | elixirc_paths: elixirc_paths(Mix.env()), 10 | compilers: [:phoenix] ++ Mix.compilers(), 11 | start_permanent: Mix.env() == :prod, 12 | deps: deps() 13 | ] 14 | end 15 | 16 | # Configuration for the OTP application. 17 | # 18 | # Type `mix help compile.app` for more information. 19 | def application do 20 | [ 21 | mod: {Webbkoll.Application, []}, 22 | included_applications: [:logger, :runtime_tools, :inets, :tzdata] 23 | ] 24 | end 25 | 26 | # Specifies which paths to compile per environment. 27 | defp elixirc_paths(:test), do: ["lib", "test/support"] 28 | defp elixirc_paths(_), do: ["lib"] 29 | 30 | # Specifies your project dependencies. 31 | # 32 | # Type `mix help deps` for examples and options. 33 | defp deps do 34 | [ 35 | {:phoenix, "~> 1.6.0"}, 36 | {:phoenix_pubsub, "~> 2.0"}, 37 | {:phoenix_html, "~> 3.0"}, 38 | {:phoenix_live_reload, "~> 1.3", only: :dev}, 39 | {:phoenix_live_dashboard, "~> 0.5"}, 40 | {:phoenix_live_view, "~> 0.18.0"}, 41 | {:gettext, "~> 0.11"}, 42 | {:plug_cowboy, "~> 2.1"}, 43 | {:plug, "~> 1.7"}, 44 | {:httpoison, "~> 1.0"}, 45 | {:floki, "~> 0.8"}, 46 | {:ex_rated, "~> 2.0"}, 47 | {:quantum, "~> 3.0"}, 48 | {:ex_machina, "~> 2.0", only: :test}, 49 | {:public_suffix, git: "https://github.com/andersju/publicsuffix-elixir.git", ref: "8937242"}, 50 | {:timex, "~> 3.0"}, 51 | {:hackney, "~> 1.8"}, 52 | {:idna, "~> 6.0"}, 53 | {:con_cache, "~> 1.0"}, 54 | {:uniq, "== 0.5.1"}, 55 | {:jason, "~> 1.0"}, 56 | {:valid_url, "~> 0.1.2"}, 57 | {:honeydew, "~> 1.5.0"}, 58 | {:remote_ip, "~> 1.0"} 59 | ] 60 | end 61 | end 62 | -------------------------------------------------------------------------------- /lib/webbkoll_web/templates/site/_request_table.html.heex: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | <%= for {{host, data}, counter} <- Enum.with_index(@requests) do %> 12 | <% host_info = List.first(data) %> 13 | 14 | 30 | 31 | 32 | 33 | 34 | <% end %> 35 | 36 |
<%= gettext "Host" %><%= gettext "IP" %><%= gettext "Classification" %><%= gettext "URLs" %>
15 | <%= host %> 16 | 17 |
    18 | <%= for request <- data do %> 19 |
  • 20 | <%= if String.starts_with?(request.url, "https") do %> 21 | 22 | <% else %> 23 | 24 | <% end %> 25 | <%= link "#{truncate(request.url, 70)}", to: request.url %> 26 |
  • 27 | <% end %> 28 |
29 |
<%= host_info.ip %><%= Webbkoll.Trackers.check(PublicSuffix.registrable_domain(host, ignore_private: true)) %><%= gettext("Show") %> (<%= Enum.count(data) %>)
37 | 38 |

<%= gettext(~s|We use Mozilla's version of Disconnect's open source list of trackers to classify hosts.|, url_mozilla: "https://github.com/mozilla-services/shavar-prod-lists", url_disconnect: "https://github.com/disconnectme/disconnect-tracking-protection") |> raw %>

39 | -------------------------------------------------------------------------------- /assets/scss/.sass-cache/72dda0c11013fc7994d6c543544dc280a238d0cf/_appearance.scssc: -------------------------------------------------------------------------------- 1 | 3.4.21 (Selective Steve) 2 | 3e3b77ca8717a4a8fb3d4309b1db9fd8a47d2dca 3 | o:Sass::Tree::RootNode :@children[o:Sass::Tree::MixinDefNode : 4 | @nameI"appearance:ET: 5 | @args[[o:!Sass::Script::Tree::Variable ;I" 6 | value; T:@underscored_nameI" 7 | value; T: 8 | @linei:@source_rangeo:Sass::Source::Range :@start_poso:Sass::Source::Position; i: @offseti: @end_poso;; i;i: 9 | @fileI""bourbon/css3/_appearance.scss; T:@importero: Sass::Importers::Filesystem: 10 | @rootI"A/home/andersju/jobb/dataskydd/syzygy/bourbontest/stylesheets; T:@real_rootI"A/home/andersju/jobb/dataskydd/syzygy/bourbontest/stylesheets; T:@same_name_warningso:Set: 11 | @hash}F:@filename@: @options{0: @splat0;[o:Sass::Tree::MixinNode;I" prefixer; T; 12 | [o: Sass::Script::Tree::Literal : @valueo: Sass::Script::Value::String ;!I"appearance; T: 13 | @type:identifier:"@deprecated_interp_equivalent0;@; i;o; ;o;; i;i;o;; i;i$;@;@;@o; ;I" 14 | value; T; I" 15 | value; T; i;o; ;o;; i;i&;o;; i;i,;@;@;@;@o:$Sass::Script::Tree::ListLiteral :@elements[ 16 | o; ;!o;" ;!I" webkit; T;#;$;%0;@; i;o; ;o;; i;i.;o;; i;i4;@;@;@o; ;!o;" ;!I"moz; T;#;$;%0;@; i;o; ;o;; i;i5;o;; i;i8;@;@;@o; ;!o;" ;!I"ms; T;#;$;%0;@; i;o; ;o;; i;i9;o;; i;i;;@;@;@o; ;!o;" ;!I"o; T;#;$;%0;@; i;o; ;o;; i;i<;o;; i;i=;@;@;@o; ;!o;" ;!I" spec; T;#;$;%0;@; i;o; ;o;; i;i>;o;; i;iB;@;@;@:@separator: 17 | space; i;o; ;o;; i;i-;o;; i;iB;@;@;@;@:@keywordso:Sass::Util::NormalizedMap:@key_strings{: @map{;0:@kwarg_splat0;[; i;o; ;o;; i;i;o;; i;iC;@;@;@; i;o; ;o;; i;i;o;; i;i ;@;@:@has_childrenT;@:@templateI"b@mixin appearance($value) { 18 | @include prefixer(appearance, $value, webkit moz ms o spec); 19 | } 20 | ; T; i;o; ;o;; i;i;o;; i;i;@;@;/T;@ -------------------------------------------------------------------------------- /assets/scss/_icons.scss: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'icomoon'; 3 | src: 4 | url('../fonts/icomoon.ttf?3whmfg') format('truetype'), 5 | url('../fonts/icomoon.woff?3whmfg') format('woff'), 6 | url('../fonts/icomoon.svg?3whmfg#icomoon') format('svg'); 7 | font-weight: normal; 8 | font-style: normal; 9 | } 10 | 11 | [class^="icon-"], [class*=" icon-"] { 12 | /* use !important to prevent issues with browser extensions that change fonts */ 13 | font-family: 'icomoon' !important; 14 | speak: none; 15 | font-style: normal; 16 | font-weight: normal; 17 | font-variant: normal; 18 | text-transform: none; 19 | line-height: 1; 20 | 21 | /* Better Font Rendering =========== */ 22 | -webkit-font-smoothing: antialiased; 23 | -moz-osx-font-smoothing: grayscale; 24 | } 25 | 26 | .icon-sort-down:before { 27 | content: "\f0dd"; 28 | } 29 | .icon-clock:before { 30 | content: "\e94e"; 31 | } 32 | .icon-search:before { 33 | content: "\e986"; 34 | } 35 | .icon-lock:before { 36 | content: "\e98f"; 37 | } 38 | .icon-unlock-alt:before { 39 | content: "\e990"; 40 | } 41 | .icon-gavel:before { 42 | content: "\e9a8"; 43 | } 44 | .icon-sphere:before { 45 | content: "\e9c9"; 46 | } 47 | .icon-link:before { 48 | content: "\e9cb"; 49 | } 50 | .icon-eye-slash:before { 51 | content: "\e9d1"; 52 | } 53 | .icon-notification:before { 54 | content: "\ea08"; 55 | } 56 | .icon-question-circle:before { 57 | content: "\ea09"; 58 | } 59 | .icon-plus:before { 60 | content: "\ea0a"; 61 | } 62 | .icon-minus:before { 63 | content: "\ea0b"; 64 | } 65 | .icon-info:before { 66 | content: "\ea0c"; 67 | } 68 | .icon-times:before { 69 | content: "\ea0f"; 70 | } 71 | .icon-check:before { 72 | content: "\ea10"; 73 | } 74 | .icon-redo:before { 75 | content: "\ea2e"; 76 | } 77 | .icon-circle-up:before { 78 | content: "\ea41"; 79 | } 80 | .icon-circle-down:before { 81 | content: "\ea43"; 82 | } 83 | .icon-check-square:before { 84 | content: "\ea52"; 85 | } 86 | .icon-new-tab:before { 87 | content: "\ea7e"; 88 | } 89 | -------------------------------------------------------------------------------- /assets/scss/.sass-cache/72dda0c11013fc7994d6c543544dc280a238d0cf/_user-select.scssc: -------------------------------------------------------------------------------- 1 | 3.4.21 (Selective Steve) 2 | 2d413db6645a8aefe9f2439edc11f4d207f44337 3 | o:Sass::Tree::RootNode :@children[o:Sass::Tree::MixinDefNode : 4 | @nameI"user-select:ET: 5 | @args[[o:!Sass::Script::Tree::Variable ;I" 6 | value; T:@underscored_nameI" 7 | value; T: 8 | @linei:@source_rangeo:Sass::Source::Range :@start_poso:Sass::Source::Position; i: @offseti: @end_poso;; i;i: 9 | @fileI"#bourbon/css3/_user-select.scss; T:@importero: Sass::Importers::Filesystem: 10 | @rootI"A/home/andersju/jobb/dataskydd/syzygy/bourbontest/stylesheets; T:@real_rootI"A/home/andersju/jobb/dataskydd/syzygy/bourbontest/stylesheets; T:@same_name_warningso:Set: 11 | @hash}F:@filename@: @options{o: Sass::Script::Tree::Literal : @valueo: Sass::Script::Value::String ;I" none; T: 12 | @type:identifier:"@deprecated_interp_equivalent0;@; i;o; ;o;; i;i!;o;; i;i%;@;@;@: @splat0;[o:Sass::Tree::MixinNode;I" prefixer; T; 13 | [o; ;o; ;I"user-select; T;!;";#0;@; i;o; ;o;; i;i;o;; i;i%;@;@;@o; ;I" 14 | value; T; I" 15 | value; T; i;o; ;o;; i;i';o;; i;i-;@;@;@;@o:$Sass::Script::Tree::ListLiteral :@elements[ o; ;o; ;I" webkit; T;!;";#0;@; i;o; ;o;; i;i/;o;; i;i5;@;@;@o; ;o; ;I"moz; T;!;";#0;@; i;o; ;o;; i;i6;o;; i;i9;@;@;@o; ;o; ;I"ms; T;!;";#0;@; i;o; ;o;; i;i:;o;; i;i<;@;@;@o; ;o; ;I" spec; T;!;";#0;@; i;o; ;o;; i;i=;o;; i;iA;@;@;@:@separator: 16 | space; i;o; ;o;; i;i.;o;; i;iA;@;@;@;@:@keywordso:Sass::Util::NormalizedMap:@key_strings{: @map{;$0:@kwarg_splat0;[; i;o; ;o;; i;i;o;; i;iB;@;@;@; i;o; ;o;; i;i;o;; i;i';@;@:@has_childrenT;@:@templateI"h@mixin user-select($value: none) { 17 | @include prefixer(user-select, $value, webkit moz ms spec); 18 | } 19 | ; T; i;o; ;o;; i;i;o;; i;i;@;@;/T;@ -------------------------------------------------------------------------------- /assets/scss/_tooltip.scss: -------------------------------------------------------------------------------- 1 | .tooltip-item { 2 | $base-border-color: gainsboro !default; 3 | $base-border-radius: 3px !default; 4 | $base-line-height: 1.5em !default; 5 | $dark-gray: #333 !default; 6 | $base-font-color: $dark-gray !default; 7 | $tooltip-background: white; 8 | $tooltip-color: $base-font-color; 9 | $tooltip-max-width: 16em; 10 | $tooltip-arrow-width: 8px; 11 | $tooltip-shadow: 0 2px 2px silver; 12 | $tooltip-distance-from-item: 3em; 13 | $tooltip-arrow-distance-from-box: -1.3em; 14 | 15 | background: $tooltip-background; 16 | border: 1px solid $base-border-color; 17 | border-radius: $base-border-radius; 18 | display: inline-block; 19 | padding: 0.5em 1em; 20 | position: relative; 21 | text-align: center; 22 | 23 | &:focus, 24 | &:hover .tooltip { 25 | opacity: 1; 26 | visibility: visible; 27 | } 28 | 29 | .tooltip { 30 | @include position(absolute, null 0 $tooltip-distance-from-item 0); 31 | background-color: $tooltip-background; 32 | background: #fff; 33 | border-radius: $base-border-radius; 34 | box-shadow: $tooltip-shadow; 35 | color: $tooltip-color; 36 | font-size: 0.9em; // Make sure you use -webkit-backface-visibility: hidden; on the body element to prevent 1px nudging bugs. 37 | line-height: 1.5em; 38 | margin: 0 auto; 39 | max-width: $tooltip-max-width; 40 | opacity: 0; 41 | padding: 1em; 42 | text-align: center; 43 | transition: all 0.2s ease-in-out; 44 | visibility: hidden; 45 | z-index: 10; 46 | 47 | p { 48 | color: $base-font-color; 49 | line-height: $base-line-height; 50 | margin: 0; 51 | } 52 | 53 | &::after { 54 | @include position(absolute, null 0); 55 | border: $tooltip-arrow-width solid transparent; 56 | bottom: $tooltip-arrow-distance-from-box; 57 | color: $tooltip-background; 58 | content: "▼"; 59 | font-size: 1.4em; 60 | margin-left: -$tooltip-arrow-width; 61 | text-align: center; 62 | text-shadow: $tooltip-shadow; 63 | } 64 | } 65 | } -------------------------------------------------------------------------------- /assets/scss/neat/settings/_grid.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Sets the relative width of a single grid column. The unit used should be the same one used to define `$gutter`. To learn more about `modular-scale()` see [Bourbon docs](http://bourbon.io/docs/#modular-scale). Set with a `!global` flag. 4 | /// 5 | /// @type Number (Unit) 6 | 7 | $column: modular-scale(3, 1em, $golden) !default; 8 | 9 | /// Sets the relative width of a single grid gutter. The unit used should be the same one used to define `$column`. To learn more about `modular-scale()` see [Bourbon docs](http://bourbon.io/docs/#modular-scale). Set with the `!global` flag. 10 | /// 11 | /// @type Number (Unit) 12 | 13 | $gutter: modular-scale(1, 1em, $golden) !default; 14 | 15 | /// Sets the total number of columns in the grid. Its value can be overridden inside a media query using the `media()` mixin. Set with the `!global` flag. 16 | /// 17 | /// @type Number (Unitless) 18 | 19 | $grid-columns: 12 !default; 20 | 21 | /// Sets the max-width property of the element that includes `outer-container()`. Set with the `!global` flag. 22 | /// 23 | /// @type Number (Unit) 24 | /// 25 | $max-width: 1300px !default; 26 | 27 | /// When set to true, it sets the box-sizing property of all elements to `border-box`. Set with a `!global` flag. 28 | /// 29 | /// @type Bool 30 | /// 31 | /// @example css - CSS Output 32 | /// html { 33 | /// box-sizing: border-box; } 34 | /// 35 | /// *, *::after, *::before { 36 | /// box-sizing: inherit; 37 | /// } 38 | 39 | $border-box-sizing: true !default; 40 | 41 | /// Sets the default [media feature](http://www.w3.org/TR/css3-mediaqueries/#media) that `media()` and `new-breakpoint()` revert to when only a breakpoint value is passed. Set with a `!global` flag. 42 | /// 43 | /// @type String 44 | 45 | $default-feature: min-width; // Default @media feature for the breakpoint() mixin 46 | 47 | ///Sets the default layout direction of the grid. Can be `LTR` or `RTL`. Set with a `!global` flag. 48 | /// 49 | ///@type String 50 | 51 | $default-layout-direction: LTR !default; 52 | -------------------------------------------------------------------------------- /assets/scss/neat/functions/_new-breakpoint.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Returns a media context (media query / grid context) that can be stored in a variable and passed to `media()` as a single-keyword argument. Media contexts defined using `new-breakpoint` are used by the visual grid, as long as they are defined before importing Neat. 4 | /// 5 | /// @param {List} $query 6 | /// A list of media query features and values. Each `$feature` should have a corresponding `$value`. 7 | /// 8 | /// If there is only a single `$value` in `$query`, `$default-feature` is going to be used. 9 | /// 10 | /// The number of total columns in the grid can be set by passing `$columns` at the end of the list (overrides `$total-columns`). For a list of valid values for `$feature`, click [here](http://www.w3.org/TR/css3-mediaqueries/#media1). 11 | /// 12 | /// @param {Number (unitless)} $total-columns [$grid-columns] 13 | /// - Number of columns to use in the new grid context. Can be set as a shorthand in the first parameter. 14 | /// 15 | /// @example scss - Usage 16 | /// $mobile: new-breakpoint(max-width 480px 4); 17 | /// 18 | /// .element { 19 | /// @include media($mobile) { 20 | /// @include span-columns(4); 21 | /// } 22 | /// } 23 | /// 24 | /// @example css - CSS Output 25 | /// @media screen and (max-width: 480px) { 26 | /// .element { 27 | /// display: block; 28 | /// float: left; 29 | /// margin-right: 7.42297%; 30 | /// width: 100%; 31 | /// } 32 | /// .element:last-child { 33 | /// margin-right: 0; 34 | /// } 35 | /// } 36 | 37 | @function new-breakpoint($query: $feature $value $columns, $total-columns: $grid-columns) { 38 | @if length($query) == 1 { 39 | $query: $default-feature nth($query, 1) $total-columns; 40 | } @else if is-even(length($query)) { 41 | $query: append($query, $total-columns); 42 | } 43 | 44 | @if is-not(belongs-to($query, $visual-grid-breakpoints)) { 45 | $visual-grid-breakpoints: append($visual-grid-breakpoints, $query, comma) !global; 46 | } 47 | 48 | @return $query; 49 | } 50 | -------------------------------------------------------------------------------- /assets/scss/bourbon/bourbon/library/_hide-visually.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Hides an element visually while still allowing the content to be accessible 4 | /// to assistive technology, e.g. screen readers. Passing `unhide` will reverse 5 | /// the affects of the hiding, which is handy for showing the element on focus, 6 | /// for example. 7 | /// 8 | /// @link https://goo.gl/Vf1TGn 9 | /// 10 | /// @argument {string} $toggle [hide] 11 | /// Accepts `hide` or `unhide`. `unhide` reverses the affects of `hide`. 12 | /// 13 | /// @example scss 14 | /// .element { 15 | /// @include hide-visually; 16 | /// 17 | /// &:active, 18 | /// &:focus { 19 | /// @include hide-visually("unhide"); 20 | /// } 21 | /// } 22 | /// 23 | /// // CSS Output 24 | /// .element { 25 | /// border: 0; 26 | /// clip: rect(1px, 1px, 1px, 1px); 27 | /// clip-path: inset(100%); 28 | /// height: 1px; 29 | /// overflow: hidden; 30 | /// padding: 0; 31 | /// position: absolute; 32 | /// width: 1px; 33 | /// } 34 | /// 35 | /// .hide-visually:active, 36 | /// .hide-visually:focus { 37 | /// clip: auto; 38 | /// clip-path: none; 39 | /// height: auto; 40 | /// overflow: visible; 41 | /// position: static; 42 | /// width: auto; 43 | /// } 44 | /// 45 | /// @since 5.0.0 46 | 47 | @mixin hide-visually($toggle: "hide") { 48 | @if not index("hide" "unhide", $toggle) { 49 | @error "`#{$toggle}` is not a valid value for the `$toggle` argument in " + 50 | "the `hide-visually` mixin. Must be either `hide` or `unhide`."; 51 | } @else if $toggle == "hide" { 52 | border: 0; 53 | clip: rect(1px, 1px, 1px, 1px); 54 | clip-path: inset(100%); 55 | height: 1px; 56 | overflow: hidden; 57 | padding: 0; 58 | position: absolute; 59 | white-space: nowrap; 60 | width: 1px; 61 | } @else if $toggle == "unhide" { 62 | clip: auto; 63 | clip-path: none; 64 | height: auto; 65 | overflow: visible; 66 | position: static; 67 | white-space: inherit; 68 | width: auto; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /lib/webbkoll_web/templates/site/_localstorage.html.heex: -------------------------------------------------------------------------------- 1 |
2 |

3 | localStorage 4 | <%= anchor_link("localstorage") %> 5 |

6 | 7 |
8 | <%= if Enum.empty?(@site.data.localStorage) do %> 9 |

<%= gettext("localStorage not used.") %>

10 | <% else %> 11 |

<%= gettext("localStorage used:") %>

12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | <%= for {key, value} <- @site.data.localStorage do %> 22 | 23 | 24 | 25 | 26 | <% end %> 27 | 28 |
<%= gettext("Key") %><%= gettext("Value") %>
<%= truncate(key, 50) %><%= truncate(value, 50) %>
29 | <% end %> 30 |
31 | 40 |
41 | -------------------------------------------------------------------------------- /assets/scss/base/_forms.scss: -------------------------------------------------------------------------------- 1 | $_form-background-color: #fff; 2 | $_form-box-shadow: inset 0 1px 3px rgba(#000, 0.06); 3 | $_form-box-shadow-focus: $_form-box-shadow, 0 0 5px rgba($action-color, 0.7); 4 | 5 | fieldset { 6 | background-color: transparent; 7 | border: 0; 8 | margin: 0; 9 | padding: 0; 10 | } 11 | 12 | legend { 13 | font-weight: 600; 14 | margin-bottom: $small-spacing / 2; 15 | padding: 0; 16 | } 17 | 18 | label { 19 | display: block; 20 | font-weight: 600; 21 | margin-bottom: $small-spacing / 2; 22 | } 23 | 24 | input, 25 | select, 26 | textarea { 27 | display: block; 28 | font-family: $base-font-family; 29 | font-size: 16px; 30 | } 31 | 32 | #{$all-text-inputs} { 33 | appearance: none; 34 | background-color: $_form-background-color; 35 | border: $base-border; 36 | border-radius: $base-border-radius; 37 | box-shadow: $_form-box-shadow; 38 | box-sizing: border-box; 39 | margin-bottom: $small-spacing; 40 | padding: $base-spacing / 3; 41 | transition: border-color $base-duration $base-timing; 42 | width: 100%; 43 | 44 | &:hover { 45 | border-color: shade($base-border-color, 20%); 46 | } 47 | 48 | &:focus { 49 | border-color: $action-color; 50 | box-shadow: $_form-box-shadow-focus; 51 | outline: none; 52 | } 53 | 54 | &:disabled { 55 | background-color: shade($_form-background-color, 5%); 56 | cursor: not-allowed; 57 | 58 | &:hover { 59 | border: $base-border; 60 | } 61 | } 62 | 63 | &::placeholder { 64 | color: tint($base-font-color, 40%); 65 | } 66 | } 67 | 68 | textarea { 69 | resize: vertical; 70 | } 71 | 72 | [type="checkbox"], 73 | [type="radio"] { 74 | display: inline; 75 | margin-right: $small-spacing / 2; 76 | } 77 | 78 | [type="file"] { 79 | margin-bottom: $small-spacing; 80 | width: 100%; 81 | } 82 | 83 | select { 84 | margin-bottom: $small-spacing; 85 | width: 100%; 86 | } 87 | 88 | [type="checkbox"], 89 | [type="radio"], 90 | [type="file"], 91 | select { 92 | &:focus { 93 | outline: $focus-outline; 94 | outline-offset: $focus-outline-offset; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /lib/webbkoll_web/controllers/api/site_controller.ex: -------------------------------------------------------------------------------- 1 | defmodule WebbkollWeb.API.SiteController do 2 | use WebbkollWeb, :controller 3 | import WebbkollWeb.ControllerHelpers 4 | import WebbkollWeb.Plugs 5 | alias Webbkoll.Sites 6 | 7 | @validate_urls Application.compile_env(:webbkoll, :validate_urls) 8 | 9 | plug(:check_for_bots when action in [:create]) 10 | plug(:scrub_params, "url" when action in [:create]) 11 | plug(:get_proper_url when action in [:create]) 12 | plug(:validate_domain when action in [:create] and @validate_urls) 13 | plug(:validate_url when action in [:create] and @validate_urls) 14 | plug(:check_if_site_exists when action in [:create]) 15 | plug(:check_rate_ip when action in [:create]) 16 | plug(:check_rate_url_host when action in [:create]) 17 | 18 | def create(%Plug.Conn{assigns: %{input_url: proper_url}} = conn, _params) do 19 | site = enqueue_site(conn, proper_url) 20 | render(conn, "show.json", site: site) 21 | end 22 | 23 | def show(conn, %{"id" => id}) do 24 | case Sites.get_site(id) do 25 | nil -> render_error(conn, 404, "ID not found") 26 | site -> render(conn, "show.json", site: site) 27 | end 28 | end 29 | 30 | def show(conn, %{"url" => url}) do 31 | url 32 | |> Sites.get_latest_from_cache() 33 | |> case do 34 | nil -> render_error(conn, 404, "URL not found among scanned sites") 35 | {_id, site} -> render(conn, "show.json", site: site) 36 | end 37 | end 38 | 39 | # Plugs 40 | 41 | defp check_if_site_exists(%Plug.Conn{assigns: %{input_url: proper_url}} = conn, _params) do 42 | case conn.params["refresh"] do 43 | "on" -> conn 44 | _ -> check_site_in_cache(conn, proper_url) 45 | end 46 | end 47 | 48 | defp check_site_in_cache(conn, proper_url) do 49 | proper_url 50 | |> Sites.get_latest_from_cache() 51 | |> handle_check_site_in_cache(conn) 52 | end 53 | 54 | defp handle_check_site_in_cache({_id, site}, conn) do 55 | conn 56 | |> render("show.json", site: site) 57 | |> halt() 58 | end 59 | 60 | defp handle_check_site_in_cache(_, conn), do: conn 61 | end 62 | -------------------------------------------------------------------------------- /assets/scss/bourbon/_bourbon.scss: -------------------------------------------------------------------------------- 1 | // Bourbon 5.1.0 2 | // https://www.bourbon.io/ 3 | // Copyright 2011-2018 thoughtbot, inc. 4 | // MIT License 5 | 6 | @import "bourbon/helpers/buttons-list"; 7 | @import "bourbon/helpers/scales"; 8 | @import "bourbon/helpers/text-inputs-list"; 9 | 10 | @import "bourbon/settings/settings"; 11 | 12 | @import "bourbon/validators/contains"; 13 | @import "bourbon/validators/contains-falsy"; 14 | @import "bourbon/validators/is-color"; 15 | @import "bourbon/validators/is-length"; 16 | @import "bourbon/validators/is-number"; 17 | @import "bourbon/validators/is-size"; 18 | 19 | @import "bourbon/utilities/assign-inputs"; 20 | @import "bourbon/utilities/compact-shorthand"; 21 | @import "bourbon/utilities/directional-property"; 22 | @import "bourbon/utilities/fetch-bourbon-setting"; 23 | @import "bourbon/utilities/font-source-declaration"; 24 | @import "bourbon/utilities/gamma"; 25 | @import "bourbon/utilities/lightness"; 26 | @import "bourbon/utilities/contrast-ratio"; 27 | @import "bourbon/utilities/unpack-shorthand"; 28 | 29 | @import "bourbon/library/border-color"; 30 | @import "bourbon/library/border-radius"; 31 | @import "bourbon/library/border-style"; 32 | @import "bourbon/library/border-width"; 33 | @import "bourbon/library/buttons"; 34 | @import "bourbon/library/clearfix"; 35 | @import "bourbon/library/contrast-switch"; 36 | @import "bourbon/library/ellipsis"; 37 | @import "bourbon/library/font-face"; 38 | @import "bourbon/library/font-stacks"; 39 | @import "bourbon/library/hide-text"; 40 | @import "bourbon/library/hide-visually"; 41 | @import "bourbon/library/margin"; 42 | @import "bourbon/library/modular-scale"; 43 | @import "bourbon/library/overflow-wrap"; 44 | @import "bourbon/library/padding"; 45 | @import "bourbon/library/position"; 46 | @import "bourbon/library/prefixer"; 47 | @import "bourbon/library/shade"; 48 | @import "bourbon/library/size"; 49 | @import "bourbon/library/strip-unit"; 50 | @import "bourbon/library/text-inputs"; 51 | @import "bourbon/library/timing-functions"; 52 | @import "bourbon/library/tint"; 53 | @import "bourbon/library/triangle"; 54 | @import "bourbon/library/value-prefixer"; 55 | -------------------------------------------------------------------------------- /lib/webbkoll_web/templates/page/index.html.heex: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /config/runtime.exs: -------------------------------------------------------------------------------- 1 | import Config 2 | 3 | # config/runtime.exs is executed for all environments, including 4 | # during releases. It is executed after compilation and before the 5 | # system starts, so it is typically used to load production configuration 6 | # and secrets from environment variables or elsewhere. Do not define 7 | # any compile-time configuration in here, as it won't be applied. 8 | # The block below contains prod specific runtime configuration. 9 | 10 | # ## Using releases 11 | # 12 | # If you use `mix release`, you need to explicitly enable the server 13 | # by passing the PHX_SERVER=true when you start it: 14 | # 15 | # PHX_SERVER=true bin/webbkoll start 16 | # 17 | # Alternatively, you can use `mix phx.gen.release` to generate a `bin/server` 18 | # script that automatically sets the env var above. 19 | if System.get_env("PHX_SERVER") do 20 | config :webbkoll, WebbkollWeb.Endpoint, server: true 21 | end 22 | 23 | if config_env() == :prod do 24 | # The secret key base is used to sign/encrypt cookies and other secrets. 25 | # A default value is used in config/dev.exs and config/test.exs but you 26 | # want to use a different value for prod and you most likely don't want 27 | # to check this value into version control, so we use an environment 28 | # variable instead. 29 | secret_key_base = 30 | System.get_env("SECRET_KEY_BASE") || 31 | raise """ 32 | environment variable SECRET_KEY_BASE is missing. 33 | You can generate one by calling: mix phx.gen.secret 34 | """ 35 | 36 | host = System.get_env("PHX_HOST") || "webbkoll.dataskydd.net" 37 | port = String.to_integer(System.get_env("PORT") || "4000") 38 | 39 | config :webbkoll, WebbkollWeb.Endpoint, 40 | http: [port: port], 41 | url: [host: host, port: 80], 42 | #url: [host: host, port: 443, scheme: "https"], 43 | #http: [ 44 | # Enable IPv6 and bind on all interfaces. 45 | # Set it to {0, 0, 0, 0, 0, 0, 0, 1} for local network only access. 46 | # See the documentation on https://hexdocs.pm/plug_cowboy/Plug.Cowboy.html 47 | # for details about using IPv6 vs IPv4 and loopback vs public addresses. 48 | # ip: {0, 0, 0, 0, 0, 0, 0, 0}, 49 | # port: port 50 | #], 51 | secret_key_base: secret_key_base 52 | end 53 | -------------------------------------------------------------------------------- /assets/scss/.sass-cache/74571de3e827f0001966c84f665e8974ed75748e/_prefixer.scssc: -------------------------------------------------------------------------------- 1 | 3.4.21 (Selective Steve) 2 | e016bbe4e404715644619f806f58262fdff92e14 3 | o:Sass::Tree::RootNode :@children[ o:Sass::Tree::CharsetNode 4 | : 5 | @nameI" 6 | UTF-8:ET;[: 7 | @linei:@source_rangeo:Sass::Source::Range :@start_poso:Sass::Source::Position; 8 | i: @offseti: @end_poso;; 9 | i;i: 10 | @fileI"$bourbon/settings/_prefixer.scss; T:@importero: Sass::Importers::Filesystem: 11 | @rootI"A/home/andersju/jobb/dataskydd/syzygy/bourbontest/stylesheets; T:@real_rootI"A/home/andersju/jobb/dataskydd/syzygy/bourbontest/stylesheets; T:@same_name_warningso:Set: 12 | @hash}F: @options{o:Sass::Tree::CommentNode : @value[I"A/*/ Global variables to enable or disable vendor prefixes */; T: 13 | @type: silent;[; 14 | i; o; ; o;; 15 | i;i;o;; 16 | i;i?;@ ;@;@o:Sass::Tree::VariableNode ;I"prefix-for-webkit; T: 17 | @expro: Sass::Script::Tree::Literal ;o:Sass::Script::Value::Bool;T;@; 18 | i 19 | ; o; ; o;; 20 | i 21 | ;i;o;; 22 | i 23 | ;i!;@ ;@:@filename@ : @guardedT: @global0;[; 24 | i 25 | ; o; ; o;; 26 | i 27 | ;i;o;; 28 | i 29 | ;i*;@ ;@;@o; ;I"prefix-for-mozilla; T;o; ;@; 30 | i ; o; ; o;; 31 | i ;i;o;; 32 | i ;i!;@ ;@;"@ ;#T;$0;[; 33 | i ; o; ; o;; 34 | i ;i;o;; 35 | i ;i*;@ ;@;@o; ;I"prefix-for-microsoft; T;o; ;@; 36 | i ; o; ; o;; 37 | i ;i;o;; 38 | i ;i!;@ ;@;"@ ;#T;$0;[; 39 | i ; o; ; o;; 40 | i ;i;o;; 41 | i ;i*;@ ;@;@o; ;I"prefix-for-opera; T;o; ;@; 42 | i ; o; ; o;; 43 | i ;i;o;; 44 | i ;i!;@ ;@;"@ ;#T;$0;[; 45 | i ; o; ; o;; 46 | i ;i;o;; 47 | i ;i*;@ ;@;@o; ;I"prefix-for-spec; T;o; ;@; 48 | i; o; ; o;; 49 | i;i;o;; 50 | i;i!;@ ;@;"@ ;#T;$0;[; 51 | i; o; ; o;; 52 | i;i;o;; 53 | i;i*;@ ;@;@:@templateI" @charset "UTF-8"; 54 | 55 | /// Global variables to enable or disable vendor prefixes 56 | 57 | $prefix-for-webkit: true !default; 58 | $prefix-for-mozilla: true !default; 59 | $prefix-for-microsoft: true !default; 60 | $prefix-for-opera: true !default; 61 | $prefix-for-spec: true !default; 62 | ; T; 63 | i; o; ; o;; 64 | i;i;o;; 65 | i;i;@ ;@:@has_childrenT;@ -------------------------------------------------------------------------------- /lib/webbkoll/helpers.ex: -------------------------------------------------------------------------------- 1 | defmodule Webbkoll.Helpers do 2 | @locales Application.compile_env(:webbkoll, :locales) 3 | 4 | def language_from_code(code), do: Map.get(@locales, code) 5 | 6 | def get_proper_ip("[" <> rest), do: String.slice(rest, 0..-2) 7 | 8 | def get_proper_ip(ip), do: ip 9 | 10 | def get_unique_hosts(data, field_name) do 11 | data 12 | |> Enum.map(& &1[field_name]) 13 | |> Enum.uniq() 14 | end 15 | 16 | def truncate(string, maximum) do 17 | case String.length(string) > maximum do 18 | true -> "#{String.slice(string, 0, maximum)}..." 19 | false -> string 20 | end 21 | end 22 | 23 | def idna_from_punycode(host) do 24 | host 25 | |> String.to_charlist() 26 | |> :idna.from_ascii() 27 | |> List.to_string() 28 | end 29 | 30 | def get_headers(url) when is_binary(url) do 31 | url 32 | |> HTTPoison.head() 33 | |> handle_get_headers() 34 | end 35 | 36 | def handle_get_headers({:ok, response}) do 37 | {:ok, Enum.map(response.headers, fn {k, v} -> {String.downcase(k), v} end)} 38 | end 39 | 40 | def handle_get_headers({:error, reason}) do 41 | {:error, reason} 42 | end 43 | 44 | def find_header(url, header) do 45 | url 46 | |> get_headers() 47 | |> handle_find_header(header) 48 | end 49 | 50 | defp handle_find_header({:error, reason}, _), do: {:error, reason} 51 | 52 | defp handle_find_header({:ok, headers}, header) do 53 | headers 54 | |> Enum.find(fn {k, _} -> k == header end) 55 | |> case do 56 | nil -> {:ok, nil} 57 | {_, v} -> {:ok, v} 58 | end 59 | end 60 | 61 | def is_third_party_domain?(url, registrable_domain) do 62 | host = URI.parse(url).host 63 | host !== nil && get_registerable_domain(host) !== registrable_domain 64 | end 65 | 66 | def get_registerable_domain(host) do 67 | case PublicSuffix.matches_explicit_rule?(host) do 68 | true -> 69 | # Workaround to handle the fact that some entities serve content directly 70 | # at the public suffix level, and we want to be able to check those too. 71 | # TODO: rename get_registerable_domain to something more appropriate. 72 | case PublicSuffix.registrable_domain(host) do 73 | nil -> host 74 | reg_domain -> reg_domain 75 | end 76 | false -> host 77 | end 78 | end 79 | end 80 | -------------------------------------------------------------------------------- /assets/scss/bourbon/bourbon/utilities/_directional-property.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | // scss-lint:disable SpaceAroundOperator 4 | 5 | /// Builds directional properties by parsing CSS shorthand values. For example, 6 | /// a value of `10px null` will output top and bottom directional properties, 7 | /// but the `null` skips left and right from being output. 8 | /// 9 | /// @argument {string} $property 10 | /// Base property. 11 | /// 12 | /// @argument {string} $suffix 13 | /// Suffix to append. Use `null` to omit. 14 | /// 15 | /// @argument {list} $values 16 | /// List of values to set for the property. 17 | /// 18 | /// @example scss 19 | /// .element { 20 | /// @include _directional-property(border, width, null 5px); 21 | /// } 22 | /// 23 | /// // CSS Output 24 | /// .element { 25 | /// border-right-width: 5px; 26 | /// border-left-width: 5px; 27 | /// } 28 | /// 29 | /// @require {function} _compact-shorthand 30 | /// 31 | /// @require {function} _contains-falsy 32 | /// 33 | /// @access private 34 | 35 | @mixin _directional-property( 36 | $property, 37 | $suffix, 38 | $values 39 | ) { 40 | $top: $property + "-top" + if($suffix, "-#{$suffix}", ""); 41 | $bottom: $property + "-bottom" + if($suffix, "-#{$suffix}", ""); 42 | $left: $property + "-left" + if($suffix, "-#{$suffix}", ""); 43 | $right: $property + "-right" + if($suffix, "-#{$suffix}", ""); 44 | $all: $property + if($suffix, "-#{$suffix}", ""); 45 | 46 | $values: _compact-shorthand($values); 47 | 48 | @if _contains-falsy($values) { 49 | @if nth($values, 1) { #{$top}: nth($values, 1); } 50 | 51 | @if length($values) == 1 { 52 | @if nth($values, 1) { #{$right}: nth($values, 1); } 53 | } @else { 54 | @if nth($values, 2) { #{$right}: nth($values, 2); } 55 | } 56 | 57 | @if length($values) == 2 { 58 | @if nth($values, 1) { #{$bottom}: nth($values, 1); } 59 | @if nth($values, 2) { #{$left}: nth($values, 2); } 60 | } @else if length($values) == 3 { 61 | @if nth($values, 3) { #{$bottom}: nth($values, 3); } 62 | @if nth($values, 2) { #{$left}: nth($values, 2); } 63 | } @else if length($values) == 4 { 64 | @if nth($values, 3) { #{$bottom}: nth($values, 3); } 65 | @if nth($values, 4) { #{$left}: nth($values, 4); } 66 | } 67 | } @else { 68 | #{$all}: $values; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /lib/webbkoll_web/templates/site/_requests.html.heex: -------------------------------------------------------------------------------- 1 |
2 | <%= if @site.data.scheme == "https" && Enum.count(@site.data.insecure_first_party_requests) > 0 do %> 3 |

4 | <%= gettext "Insecure first-party requests" %> 5 | <%= anchor_link("insecure-first-party-requests") %> 6 |

7 |
    8 | <%= for req <- @site.data.insecure_first_party_requests do %> 9 |
  • 10 | 11 | <%= req["host"] %> 12 | <%= link " (#{truncate(req["url"], 50)})", to: req["url"] %> 13 |
  • 14 | <% end %> 15 |
16 | <% end %> 17 | 18 | <%= if @site.data.third_party_request_types.total == 0 do %> 19 |

20 | <%= gettext "Third-party requests" %> 21 | <%= anchor_link("requests") %> 22 |

23 |

<%= gettext "No third-party requests." %>

24 |

<%= gettext("A third-party request is a request to a domain that's not %{domain} or one of its subdomains.", domain: @site.data.reg_domain) |> raw %>

25 | <% else %> 26 |

27 | <%= gettext "Third-party requests" %> 28 | <%= anchor_link("requests") %> 29 |

30 |

31 | <%= @site.data.third_party_request_types.total %> <%= ngettext "request", "requests", @site.data.third_party_request_types.total %> (<%= ngettext "1 secure", "%{count} secure", @site.data.third_party_request_types.secure %>, <%= ngettext "%{count} insecure", "%{count} insecure", @site.data.third_party_request_types.insecure %>) <%= gettext "to" %> <%= @site.data.third_party_request_types.unique_hosts %> <%= ngettext "unique", "unique", @site.data.third_party_request_types.unique_hosts %> <%= ngettext "host", "hosts", @site.data.third_party_request_types.unique_hosts %>. 32 |

33 |

<%= gettext("A third-party request is a request to a domain that's not %{domain} or one of its subdomains.", domain: @site.data.reg_domain) |> raw %>

34 | 35 | <%= render "_request_table.html", requests: @site.data.third_party_requests, id: "table-requests" %> 36 | 37 | <% end %> 38 | 39 |

<%= icon(:law) %> GDPR: <%= [~w|rec 69|, ~w|rec 70|, ~w|art 5 5.1.b-c|, ~w|art 25|] |> gdpr() |> raw() %>.

40 |
-------------------------------------------------------------------------------- /assets/scss/bourbon/bourbon/library/_font-face.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Generates an `@font-face` declaration. You can choose the specific file 4 | /// formats you need to output; the mixin supports `eot`, `ttf`, `svg`, `woff2` 5 | /// and `woff`. The mixin also supports usage with the Rails Asset Pipeline, 6 | /// which you can enable per use, or globally in the `$bourbon()` settings. 7 | /// 8 | /// @argument {string} $font-family 9 | /// 10 | /// @argument {string} $file-path 11 | /// 12 | /// @argument {string | list} $file-formats [("ttf", "woff2", "woff")] 13 | /// List of the font file formats to include. Can also be set globally using 14 | /// the `global-font-file-formats` key in the Bourbon settings. 15 | /// 16 | /// @argument {string} $asset-pipeline [false] 17 | /// Set to `true` if you’re using the Rails Asset Pipeline (place the fonts 18 | /// in `app/assets/fonts/`). Can also be set globally using the 19 | /// `rails-asset-pipeline` key in the Bourbon settings. 20 | /// 21 | /// @content 22 | /// Any additional CSS properties that are included in the `@include` 23 | /// directive will be output within the `@font-face` declaration, e.g. you can 24 | /// pass in `font-weight`, `font-style` and/or `unicode-range`. 25 | /// 26 | /// @example scss 27 | /// @include font-face( 28 | /// "source-sans-pro", 29 | /// "fonts/source-sans-pro-regular", 30 | /// ("woff2", "woff") 31 | /// ) { 32 | /// font-style: normal; 33 | /// font-weight: 400; 34 | /// } 35 | /// 36 | /// // CSS Output 37 | /// @font-face { 38 | /// font-family: "source-sans-pro"; 39 | /// src: url("fonts/source-sans-pro-regular.woff2") format("woff2"), 40 | /// url("fonts/source-sans-pro-regular.woff") format("woff"); 41 | /// font-style: normal; 42 | /// font-weight: 400; 43 | /// } 44 | /// 45 | /// @require {function} _font-source-declaration 46 | /// 47 | /// @require {function} _fetch-bourbon-setting 48 | 49 | @mixin font-face( 50 | $font-family, 51 | $file-path, 52 | $file-formats: _fetch-bourbon-setting("global-font-file-formats"), 53 | $asset-pipeline: _fetch-bourbon-setting("rails-asset-pipeline") 54 | ) { 55 | @font-face { 56 | font-family: $font-family; 57 | src: _font-source-declaration( 58 | $font-family, 59 | $file-path, 60 | $asset-pipeline, 61 | $file-formats 62 | ); 63 | @content; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /assets/scss/bourbon/bourbon/library/_border-radius.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /// Provides a concise, one-line method for setting `border-radius` on both the 4 | /// top-left and top-right of a box. 5 | /// 6 | /// @argument {number (with unit)} $radii 7 | /// 8 | /// @example scss 9 | /// .element { 10 | /// @include border-top-radius(4px); 11 | /// } 12 | /// 13 | /// // CSS Output 14 | /// .element { 15 | /// border-top-left-radius: 4px; 16 | /// border-top-right-radius: 4px; 17 | /// } 18 | 19 | @mixin border-top-radius($radii) { 20 | border-top-left-radius: $radii; 21 | border-top-right-radius: $radii; 22 | } 23 | 24 | /// Provides a concise, one-line method for setting `border-radius` on both the 25 | /// top-right and bottom-right of a box. 26 | /// 27 | /// @argument {number (with unit)} $radii 28 | /// 29 | /// @example scss 30 | /// .element { 31 | /// @include border-right-radius(3px); 32 | /// } 33 | /// 34 | /// // CSS Output 35 | /// .element { 36 | /// border-bottom-right-radius: 3px; 37 | /// border-top-right-radius: 3px; 38 | /// } 39 | 40 | @mixin border-right-radius($radii) { 41 | border-bottom-right-radius: $radii; 42 | border-top-right-radius: $radii; 43 | } 44 | 45 | /// Provides a concise, one-line method for setting `border-radius` on both the 46 | /// bottom-left and bottom-right of a box. 47 | /// 48 | /// @argument {number (with unit)} $radii 49 | /// 50 | /// @example scss 51 | /// .element { 52 | /// @include border-bottom-radius(2px); 53 | /// } 54 | /// 55 | /// // CSS Output 56 | /// .element { 57 | /// border-bottom-left-radius: 2px; 58 | /// border-bottom-right-radius: 2px; 59 | /// } 60 | 61 | @mixin border-bottom-radius($radii) { 62 | border-bottom-left-radius: $radii; 63 | border-bottom-right-radius: $radii; 64 | } 65 | 66 | /// Provides a concise, one-line method for setting `border-radius` on both the 67 | /// top-left and bottom-left of a box. 68 | /// 69 | /// @argument {number (with unit)} $radii 70 | /// 71 | /// @example scss 72 | /// .element { 73 | /// @include border-left-radius(1px); 74 | /// } 75 | /// 76 | /// // CSS Output 77 | /// .element { 78 | /// border-bottom-left-radius: 1px; 79 | /// border-top-left-radius: 1px; 80 | /// } 81 | 82 | @mixin border-left-radius($radii) { 83 | border-bottom-left-radius: $radii; 84 | border-top-left-radius: $radii; 85 | } 86 | -------------------------------------------------------------------------------- /assets/scss/bourbon/bourbon/library/_buttons.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | //// 4 | /// @type list 5 | /// 6 | /// @require {function} _assign-inputs 7 | /// 8 | /// @require {variable} $_buttons-list 9 | //// 10 | 11 | /// A list of all HTML button elements. Please note that you must interpolate 12 | /// the variable (`#{}`) to use it as a selector. 13 | /// 14 | /// @example scss 15 | /// #{$all-buttons} { 16 | /// background-color: #f00; 17 | /// } 18 | /// 19 | /// // CSS Output 20 | /// button, 21 | /// [type='button'], 22 | /// [type='reset'], 23 | /// [type='submit'] { 24 | /// background-color: #f00; 25 | /// } 26 | 27 | $all-buttons: _assign-inputs($_buttons-list); 28 | 29 | /// A list of all HTML button elements with the `:active` pseudo-class applied. 30 | /// Please note that you must interpolate the variable (`#{}`) to use it as a 31 | /// selector. 32 | /// 33 | /// @example scss 34 | /// #{$all-buttons-active} { 35 | /// background-color: #00f; 36 | /// } 37 | /// 38 | /// // CSS Output 39 | /// button:active, 40 | /// [type='button']:active, 41 | /// [type='reset']:active, 42 | /// [type='submit']:active { 43 | /// background-color: #00f; 44 | /// } 45 | 46 | $all-buttons-active: _assign-inputs($_buttons-list, active); 47 | 48 | /// A list of all HTML button elements with the `:focus` pseudo-class applied. 49 | /// Please note that you must interpolate the variable (`#{}`) to use it as a 50 | /// selector. 51 | /// 52 | /// @example scss 53 | /// #{$all-buttons-focus} { 54 | /// background-color: #0f0; 55 | /// } 56 | /// 57 | /// // CSS Output 58 | /// button:focus, 59 | /// [type='button']:focus, 60 | /// [type='reset']:focus, 61 | /// [type='submit']:focus { 62 | /// background-color: #0f0; 63 | /// } 64 | 65 | $all-buttons-focus: _assign-inputs($_buttons-list, focus); 66 | 67 | /// A list of all HTML button elements with the `:hover` pseudo-class applied. 68 | /// Please note that you must interpolate the variable (`#{}`) to use it as a 69 | /// selector. 70 | /// 71 | /// @example scss 72 | /// #{$all-buttons-hover} { 73 | /// background-color: #0f0; 74 | /// } 75 | /// 76 | /// // CSS Output 77 | /// button:hover, 78 | /// [type='button']:hover, 79 | /// [type='reset']:hover, 80 | /// [type='submit']:hover { 81 | /// background-color: #0f0; 82 | /// } 83 | 84 | $all-buttons-hover: _assign-inputs($_buttons-list, hover); 85 | -------------------------------------------------------------------------------- /lib/webbkoll/trackers.ex: -------------------------------------------------------------------------------- 1 | defmodule Webbkoll.Trackers do 2 | # Make sure trackers.ex is recompiled if services.json changes 3 | @external_resource Application.app_dir(:webbkoll, "priv/services.json") 4 | 5 | # We want to be able to match domains against Disconnect's open source list 6 | # of trackers (https://github.com/disconnectme/disconnect-tracking-protection 7 | # or Mozilla's version https://github.com/mozilla-services/shavar-prod-lists), 8 | # however their services.json has the actual domains a few levels deep in the 9 | # structure. The following parses the JSON file and creates a map where each 10 | # unique host is a key. Additionally, by making this a module attribute, we 11 | # ensure that this is only done at compile time. 12 | @hosts (fn -> 13 | Application.app_dir(:webbkoll, "priv/services.json") 14 | |> File.read!() 15 | |> Jason.decode!() 16 | |> Map.get("categories") 17 | |> Enum.reduce(%{}, fn {category, sites}, hosts -> 18 | Enum.reduce(sites, hosts, fn site, hosts -> 19 | Enum.reduce(site, hosts, fn {name, url}, hosts -> 20 | url 21 | |> Enum.filter(fn {x, _y} -> String.starts_with?(x, ["http", "www."]) end) 22 | |> Enum.into(%{}) 23 | |> Map.values() 24 | |> List.first([]) 25 | |> Enum.reduce(hosts, fn host, hosts -> 26 | if Map.has_key?(hosts, host) do 27 | new_map = %{ 28 | hosts[host] 29 | | "category" => [category | hosts[host]["category"]] 30 | } 31 | 32 | Map.put(hosts, host, new_map) 33 | else 34 | Map.put_new(hosts, host, %{"category" => [category], "name" => name}) 35 | end 36 | end) 37 | end) 38 | end) 39 | end) 40 | |> Enum.map(fn {k, v} -> 41 | {k, "#{Enum.join(v["category"], ", ")} (#{v["name"]})"} 42 | end) 43 | |> Enum.into(%{}) 44 | end).() 45 | 46 | def check(host) do 47 | case Map.fetch(@hosts, host) do 48 | {:ok, value} -> 49 | value 50 | 51 | :error -> 52 | if to_string(host) =~ ~r/^www\./ do 53 | check(Regex.replace(~r/^www\./, host, "")) 54 | else 55 | nil 56 | end 57 | end 58 | end 59 | end 60 | -------------------------------------------------------------------------------- /config/config.exs: -------------------------------------------------------------------------------- 1 | # This file is responsible for configuring your application 2 | # and its dependencies with the aid of the Mix.Config module. 3 | # 4 | # This configuration file is loaded before any dependency and 5 | # is restricted to this project. 6 | import Config 7 | 8 | # General application configuration 9 | config :webbkoll, 10 | locales: %{ 11 | "en" => "English", 12 | "sv" => "Svenska", 13 | "de" => "Deutsch", 14 | "no" => "Norsk", 15 | "it" => "Italiano" 16 | # "fr" => "Français" 17 | }, 18 | default_locale: "en", 19 | version: System.cmd("git", ["log", "-1", "--format=%h %ci"]) |> elem(0) |> String.trim() 20 | 21 | # Configures the endpoint 22 | config :webbkoll, WebbkollWeb.Endpoint, 23 | url: [host: "localhost"], 24 | render_errors: [accepts: ~w(html json)], 25 | pubsub_server: Webbkoll.PubSub, 26 | server: true 27 | 28 | config :webbkoll, 29 | backends: [ 30 | {Webbkoll.Queue.Q1, %{concurrency: 40, url: "http://localhost:8100/"}}, 31 | ], 32 | max_attempts: 2, 33 | # validate_urls: If true, only check URLs with a valid domain name 34 | # (i.e. ones with a TLD in the Public Suffix List), 35 | # and only the standard HTTP/HTTPS ports. 36 | validate_urls: true, 37 | # check_host_only: If true, throw away path and query parameters from submitted URLs 38 | # before passing them on to the backend. (Only works if validate_urls is also true.) 39 | check_host_only: false, 40 | # rate_limit_client: An IP address can make new site checks during milliseconds. 41 | # rate_limit_host: The tool will query a specific host no more than times during milliseconds. 42 | # See https://github.com/grempe/ex_rated 43 | rate_limit_client: %{"scale" => 60_000, "limit" => 20}, 44 | rate_limit_host: %{"scale" => 60_000, "limit" => 5} 45 | 46 | config :webbkoll, Webbkoll.Scheduler, 47 | jobs: [ 48 | {"* * * * *", {Webbkoll.CronJobs, :find_and_remove_stuck_records, []}} 49 | ] 50 | 51 | # Configures Elixir's Logger 52 | config :logger, :console, 53 | format: "$time $metadata[$level] $message\n", 54 | metadata: [:request_id], 55 | level: :error 56 | 57 | # Use Jason for JSON parsing in Phoenix 58 | config :phoenix, :json_library, Jason 59 | 60 | # Configure phoenix generators 61 | config :phoenix, :generators, 62 | migration: true, 63 | binary_id: false 64 | 65 | config :public_suffix, download_data_on_compile: true 66 | 67 | # Import environment specific config. This must remain at the bottom 68 | # of this file so it overrides the configuration defined above. 69 | import_config "#{config_env()}.exs" -------------------------------------------------------------------------------- /assets/static/js/html5shiv.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @preserve HTML5 Shiv 3.7.3 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed 3 | */ 4 | !function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=t.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=t.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),t.elements=c+" "+a,j(b)}function f(a){var b=s[a[q]];return b||(b={},r++,a[q]=r,s[r]=b),b}function g(a,c,d){if(c||(c=b),l)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():p.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||o.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),l)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return t.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(t,b.frag)}function j(a){a||(a=b);var d=f(a);return!t.shivCSS||k||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),l||i(a,d),a}var k,l,m="3.7.3",n=a.html5||{},o=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,p=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,q="_html5shiv",r=0,s={};!function(){try{var a=b.createElement("a");a.innerHTML="",k="hidden"in a,l=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){k=!0,l=!0}}();var t={elements:n.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:m,shivCSS:n.shivCSS!==!1,supportsUnknownElements:l,shivMethods:n.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=t,j(b),"object"==typeof module&&module.exports&&(module.exports=t)}("undefined"!=typeof window?window:this,document); -------------------------------------------------------------------------------- /assets/scss/.sass-cache/72dda0c11013fc7994d6c543544dc280a238d0cf/_calc.scssc: -------------------------------------------------------------------------------- 1 | 3.4.21 (Selective Steve) 2 | 439d47eeb03de4e5b437294062bf159ffddd0c19 3 | o:Sass::Tree::RootNode :@children[o:Sass::Tree::MixinDefNode : 4 | @nameI" calc:ET: 5 | @args[[o:!Sass::Script::Tree::Variable ;I" property; T:@underscored_nameI" property; T: 6 | @linei:@source_rangeo:Sass::Source::Range :@start_poso:Sass::Source::Position; i: @offseti: @end_poso;; i;i: 7 | @fileI"bourbon/css3/_calc.scss; T:@importero: Sass::Importers::Filesystem: 8 | @rootI"A/home/andersju/jobb/dataskydd/syzygy/bourbontest/stylesheets; T:@real_rootI"A/home/andersju/jobb/dataskydd/syzygy/bourbontest/stylesheets; T:@same_name_warningso:Set: 9 | @hash}F:@filename@: @options{0[o; ;I" 10 | value; T; I" 11 | value; T; i;o; ;o;; i;i;o;; i;i#;@;@;@;@0: @splat0;[o:Sass::Tree::PropNode;[o:&Sass::Script::Tree::Interpolation: @before0: @mido; ;I" property; T; I" property; T; i;o; ;o;; i;i 12 | ;o;; i;i;@;@;@;@: @after0:@whitespace_beforeF:@whitespace_afterF:@originally_textF:@warn_for_color:warn_for_color:@deprecation: none;@; i;o; ;o;; i;i;o;; i;i;@;@;@: @valueo; ;!o: Sass::Script::Tree::Literal ;+o: Sass::Script::Value::String ;+I"-webkit-calc(; T: 13 | @type:identifier:"@deprecated_interp_equivalent0;@; i;o; ;o;; i;i;o;; i;i%;@;@;@;"o; ;I" 14 | value; T; I" 15 | value; T; i;o; ;o;; i;i%;o;; i;i+;@;@;@;@;#o;, ;+o;- ;+I"); T;.;/;00;@; i;o; ;o;; i;i,;o;; i;i-;@;@;@;$F;%F;&F;'F;);*;@; i;o; ;@1;o;; i;i-;@;@;@: 16 | @tabsi:@prop_syntax:new;[; i;o; ;o;; i;i;o;; i;i-;@;@:@name_source_rangeo; ;@C;o;; i;i;@;@:@value_source_rangeo; ;o;; i;i;@D;@;@;@o;;[o; ;!0;"o; ;I" property; T; I" property; T; i;o; ;o;; i;i 17 | ;o;; i;i;@;@;@;@;#0;$F;%F;&F;';(;);*;@; i;o; ;o;; i;i;o;; i;i;@;@;@;+o; ;!o;, ;+o;- ;+I" 18 | calc(; T;.;/;00;@; i;o; ;o;; i;i;o;; i;i;@;@;@;"o; ;I" 19 | value; T; I" 20 | value; T; i;o; ;o;; i;i;o;; i;i#;@;@;@;@;#o;, ;+o;- ;+I"); T;.;/;00;@; i;o; ;o;; i;i$;o;; i;i%;@;@;@;$F;%F;&F;'F;);*;@; i;o; ;@Z;o;; i;i%;@;@;@;1i;2;3;[; i;o; ;o;; i;i;o;; i;i%;@;@;4o; ;@l;o;; i;i;@;@;5o; ;o;; i;i;@m;@;@;@; i;o; ;o;; i;i;o;; i;i%;@;@:@has_childrenT;@:@templateI"r@mixin calc($property, $value) { 21 | #{$property}: -webkit-calc(#{$value}); 22 | #{$property}: calc(#{$value}); 23 | } 24 | ; T; i;o; ;o;; i;i;o;; i;i;@;@;6T;@ -------------------------------------------------------------------------------- /lib/webbkoll_web/templates/site/_geolocation.html.heex: -------------------------------------------------------------------------------- 1 |
2 |

3 | <%= gettext "IP address" %> 4 | <%= anchor_link("server-location") %> 5 |

6 |
7 |

<%= gettext(~s|The server %{domain} had the IP address %{host_ip} during our test.|, domain: @site.data.host, host_ip: @site.data.host_ip) |> raw %>

8 | 9 |

<%= gettext(~s|You can find information about this IP address using third-party tools such as the following:|) %>

10 | 11 | 16 | 17 |

<%= gettext(~s|When using tools that do geolocation, please note that the estimated country can be wrong, especially for websites that use CDNs.|) %>

18 |
19 | 33 |
34 | -------------------------------------------------------------------------------- /assets/static/js/webbkoll-10-tablesort.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * tablesort v5.1.0 (2018-09-14) 3 | * http://tristen.ca/tablesort/demo/ 4 | * Copyright (c) 2018 ; Licensed MIT 5 | */ 6 | !function(){function a(b,c){if(!(this instanceof a))return new a(b,c);if(!b||"TABLE"!==b.tagName)throw new Error("Element must be a table");this.init(b,c||{})}var b=[],c=function(a){var b;return window.CustomEvent&&"function"==typeof window.CustomEvent?b=new CustomEvent(a):(b=document.createEvent("CustomEvent"),b.initCustomEvent(a,!1,!1,void 0)),b},d=function(a){return a.getAttribute("data-sort")||a.textContent||a.innerText||""},e=function(a,b){return a=a.trim().toLowerCase(),b=b.trim().toLowerCase(),a===b?0:a0)if(a.tHead&&a.tHead.rows.length>0){for(e=0;e0&&l.push(k),m++;if(!l)return}for(m=0;m