Merge branch 'master' into master

This commit is contained in:
Brian Lovin 2019-12-26 23:24:23 -05:00 committed by GitHub
commit 2c14183ce5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
29 changed files with 9129 additions and 11973 deletions

View file

@ -1,126 +1,31 @@
{
"extends": [
"airbnb",
"prettier",
"plugin:react/recommended"
"eslint:recommended",
"plugin:react/recommended",
"plugin:@typescript-eslint/recommended",
"prettier/@typescript-eslint",
"plugin:prettier/recommended"
],
"parser": "babel-eslint",
"parserOptions": {
"ecmaVersion": 8,
"ecmaFeatures": {
"experimentalObjectRestSpread": true,
"impliedStrict": true,
"classes": true
}
},
"plugins": ["react", "@typescript-eslint", "prettier"],
"env": {
"browser": true,
"node": true,
"jquery": true,
"jasmine": true,
"jest": true
},
"rules": {
"no-debugger": 0,
"no-alert": 0,
"no-unused-vars": [
1,
{
"ignoreSiblings": true,
"argsIgnorePattern": "res|next|^err"
}
],
"prefer-const": [
"error",
{
"destructuring": "all"
}
],
"arrow-body-style": [
2,
"as-needed"
],
"no-unused-expressions": [
2,
{
"allowTaggedTemplates": true
}
],
"no-param-reassign": [
2,
{
"props": false
}
],
"no-console": 0,
"import/prefer-default-export": 0,
"import": 0,
"func-names": 0,
"space-before-function-paren": 0,
"comma-dangle": 0,
"max-len": 0,
"import/extensions": 0,
"no-underscore-dangle": 0,
"consistent-return": 0,
"react/display-name": 1,
"react/no-array-index-key": 0,
"react/react-in-jsx-scope": 0,
"react/prefer-stateless-function": 0,
"react/forbid-prop-types": 0,
"react/no-unescaped-entities": 0,
"jsx-a11y/accessible-emoji": 0,
"react/jsx-one-expression-per-line": 0,
"react/require-default-props": 0,
"react/jsx-filename-extension": [
1,
{
"extensions": [
".js",
".jsx"
]
}
],
"radix": 0,
"no-shadow": [
2,
{
"hoist": "all",
"allow": [
"resolve",
"reject",
"done",
"next",
"err",
"error"
]
}
],
"quotes": [
2,
"single",
{
"avoidEscape": true,
"allowTemplateLiterals": true
}
],
"prettier/prettier": [
"error",
{
"trailingComma": "es5",
"singleQuote": true,
"printWidth": 80
}
],
"jsx-a11y/href-no-hash": "off",
"jsx-a11y/anchor-is-valid": [
"warn",
{
"aspects": [
"invalidHref"
]
}
]
"prettier/prettier": ["error", { "singleQuote": true }],
"react/display-name": "off",
"react/react-in-jsx-scope": "off",
"@typescript-eslint/explicit-function-return-type": "off",
"@typescript-eslint/camelcase": "off",
"@typescript-eslint/ban-ts-ignore": "off",
"@typescript-eslint/no-explicit-any": "off"
},
"plugins": [
"prettier"
]
"settings": {
"react": {
"pragma": "React",
"version": "detect"
}
},
"parser": "@typescript-eslint/parser"
}

View file

@ -11,7 +11,7 @@ suppress_comment=.*\\$FlowFixMe
suppress_comment=.*\\$FlowIssue
esproposal.class_instance_fields=enable
module.system.node.resolve_dirname=node_modules
module.system.node.resolve_dirname=.
module.system.node.allow_root_relative=true
module.file_ext=.js
module.file_ext=.jsx
module.file_ext=.json
@ -21,6 +21,3 @@ untyped-type-import=error
untyped-import=warn
unclear-type=warn
unsafe-getters-setters=error
[version]
0.95.1

4
.github/release-drafter.yml vendored Normal file
View file

@ -0,0 +1,4 @@
template: |
## Changes since last release
$CHANGES

22
.github/workflows/main.yml vendored Normal file
View file

@ -0,0 +1,22 @@
name: E2E on Chrome
on:
push:
branches:
- master
pull_request:
branches:
- master
jobs:
cypress-run:
runs-on: ubuntu-latest
# let's make sure our tests pass on Chrome browser
name: E2E on Chrome
steps:
- name: Checkout
uses: actions/checkout@v1
- name: Cypress run
uses: cypress-io/github-action@v1
with:
build: yarn run build
start: yarn run start
browser: chrome

3
.nowignore Normal file
View file

@ -0,0 +1,3 @@
cypress
README.md
package-lock.json

View file

@ -1,19 +0,0 @@
language: node_js
node_js:
- 10
cache:
directories:
- ~/.npm
- ~/.cache
install:
- npm install
before_script:
- npm run build
- npm run start &
script:
- node --version
- npm --version
- npm run flow
- npm run cypress:run
notifications:
email: false

View file

@ -23,7 +23,7 @@ If you would like to create a new category of security and privacy resources, pl
5. View the running app in your browser at `http://localhost:3000`
### Deploying
You can deploy this project yourself with ZEIT + Now by configuring `now.json` and running `$ now`. You should change the Google Analytics tag in `lib/gtag.js` and the Sentry DSN url in `pages/_app.js`.
You can deploy this project yourself with ZEIT + Now by configuring `now.json` and running `$ now`.
### Feedback
Please open issues at any time for general feedback, or you can reach me directly at hi@brianlovin.com.

View file

@ -28,6 +28,7 @@ export default function CopyLinkButton(props: CopyLinkProps) {
isClicked={isClicked}
aria-label="Copy the websites address to your clipboard."
type="button"
// $FlowIssue
{...props}
>
<Icon glyph="link" size={24} />

View file

@ -64,7 +64,7 @@ export const Apps = ({ resource, handleAppsExpand }: Props) => {
aria-expanded={overflowExpanded}
aria-controls={`apps_${resource.id}`}
>
<Button type="button">Show {overflowExpanded ? "less" : "more"} choices</Button>
<Button type="button">Show {overflowExpanded ? "fewer" : "more"} choices</Button>
</ExpandContainer>
</React.Fragment>
)}

View file

@ -16,7 +16,6 @@ import {
InnerContainer,
ScrollToTop,
} from './style';
import * as gtag from '../../lib/gtag';
import { getLocalStorageLength } from '../../lib/localStorage';
import data from '../../config/data';
@ -31,7 +30,6 @@ const totalItemsCount = Object.keys(data).length;
export default function Page(props: Props) {
const { children, displayProgress } = props;
const [lastTrackedPageview, setLastTrackedPageview] = useState(null);
const [showHeaderShadow, setHeaderShadow] = useState(false);
const [scrollToTopVisible, setScrollToTopVisible] = useState(false);
const [progress, setProgress] = useState(0);
@ -48,10 +46,10 @@ export default function Page(props: Props) {
function updateProgress() {
const checkedItemsCount = getLocalStorageLength();
const progressPercentage = checkedItemsCount * 100 / totalItemsCount;
const progressPercentage = (checkedItemsCount * 100) / totalItemsCount;
setProgress(progressPercentage);
setCurrentCount(checkedItemsCount);
};
}
const scrollToTop = () => {
if (window) {
@ -69,32 +67,21 @@ export default function Page(props: Props) {
return () => {
if (window) {
window.removeEventListener('scroll', throttledScroll);
setLastTrackedPageview(null);
}
};
}, [progress]);
useEffect(() => {
if (window && displayProgress) {
window.addEventListener('storage:updated', updateProgress );
window.addEventListener('storage:updated', updateProgress);
}
return () => {
if (window && displayProgress) {
window.removeEventListener('storage:updated', updateProgress );
window.removeEventListener('storage:updated', updateProgress);
}
};
});
useEffect(() => {
if (document) {
const newLocation = document.location.pathname;
if (newLocation !== lastTrackedPageview) {
gtag.pageview(document.location.pathname);
setLastTrackedPageview(newLocation);
}
}
});
return (
<ThemeProvider theme={theme}>
<Container>
@ -102,9 +89,10 @@ export default function Page(props: Props) {
:root {
--progress: ${progress ? 100 - progress : 100}%;
}
`}</style>
`}
</style>
<Header
<Header
showHeaderShadow={showHeaderShadow}
displayProgress={displayProgress}
totalItemsCount={totalItemsCount}

View file

@ -0,0 +1,107 @@
import { ThemeProvider } from 'styled-components';
import Head from 'next/head';
import { DefaultSeo } from 'next-seo';
import { GlobalStyles } from '../../static/normalize';
import SEO from '../../config/next-seo';
import { theme } from '../theme';
interface Props {
children?: any;
}
export default function Providers({ children }: Props) {
return (
<>
<DefaultSeo {...SEO} />
<Head>
<meta name="theme-color" content="#FFF" key="theme-color" />
<meta
name="description"
content="A checklist for staying safe on the internet"
/>
<link
rel="apple-touch-icon"
sizes="57x57"
href="/static/apple-icon-57x57.png"
/>
<link
rel="apple-touch-icon"
sizes="60x60"
href="/static/apple-icon-60x60.png"
/>
<link
rel="apple-touch-icon"
sizes="72x72"
href="/static/apple-icon-72x72.png"
/>
<link
rel="apple-touch-icon"
sizes="76x76"
href="/static/apple-icon-76x76.png"
/>
<link
rel="apple-touch-icon"
sizes="114x114"
href="/static/apple-icon-114x114.png"
/>
<link
rel="apple-touch-icon"
sizes="120x120"
href="/static/apple-icon-120x120.png"
/>
<link
rel="apple-touch-icon"
sizes="144x144"
href="/static/apple-icon-144x144.png"
/>
<link
rel="apple-touch-icon"
sizes="152x152"
href="/static/apple-icon-152x152.png"
/>
<link
rel="apple-touch-icon"
sizes="180x180"
href="/static/apple-icon-180x180.png"
/>
<link
rel="icon"
type="image/png"
sizes="192x192"
href="/static/android-icon-192x192.png"
/>
<link
rel="icon"
type="image/png"
sizes="32x32"
href="/static/favicon-32x32.png"
/>
<link
rel="icon"
type="image/png"
sizes="96x96"
href="/static/favicon-96x96.png"
/>
<link
rel="icon"
type="image/png"
sizes="16x16"
href="/static/favicon-16x16.png"
/>
<link rel="manifest" href="/static/manifest.json" />
<meta name="msapplication-TileImage" content="/ms-icon-144x144.png" />
<link rel="mask-icon" href="/static/pinned-tab.svg" color="#FFF" />
<meta name="msapplication-TileColor" content="#ffffff" />
</Head>
<GlobalStyles />
<ThemeProvider theme={theme}>
{children}
</ThemeProvider>
</>
);
}

View file

@ -62,6 +62,7 @@ export default {
windows: 'https://vivaldi.com/download/',
macos: 'https://vivaldi.com/download/',
linux: 'https://vivaldi.com/download/',
android: 'https://vivaldi.com/android/',
},
},
{

View file

@ -8,7 +8,7 @@ export default {
{
name: 'Why you should encrypt your computer',
url:
'https://www.aheliotech.com/tutorials/why-you-should-encrypt-your-computer/',
'https://theintercept.com/2015/04/27/encrypting-laptop-like-mean/',
},
{
name:

View file

@ -4,6 +4,16 @@ export default {
description: `Over the years social media companies are able to gather staggering amounts of data about you, your interests, who you talk to, where you go, what you buy, and so much more.
\n\nIf youre not ready to give up social media quite yet, you should take the time to review your security and privacy settings. Visualizing the amount of information that social media companies know about you may be enough to curb that unhealthy newsfeed obsession.`,
apps: [
{
name: 'Jumbo',
image: '/static/img/jumbo.png',
url: 'https://www.jumboprivacy.com/',
sources: {
ios: 'https://apps.apple.com/us/app/jumbo-privacy/id1454039975'
}
}
],
resources: [
{
name: 'Facebook privacy settings',

View file

@ -34,6 +34,10 @@ export default {
name: 'ExpressVPN',
image: '/static/img/expressvpn.jpg',
url: 'https://www.expressvpn.com/',
offer: {
label: 'Get 30 days free',
url: 'https://www.expressrefer.com/refer-friend?referrer_id=44490458&utm_campaign=referrals&utm_medium=copy_link&utm_source=referral_dashboard',
},
sources: {
windows: 'https://www.expressvpn.com/vpn-software/vpn-windows',
macos: 'https://www.expressvpn.com/vpn-software/vpn-mac',
@ -96,7 +100,15 @@ export default {
ios: ' https://www.purevpn.com/download/ios-vpn',
android: 'https://www.purevpn.com/download/android-vpn',
linux:'https://www.purevpn.com/download/linux-vpn',
},
}
},
{
name: 'Guardian Firewall',
image: '/static/img/guardian.png',
url: 'https://guardianapp.com',
sources: {
ios: 'https://itunes.apple.com/us/app/guardian-firewall/id1363796315'
}
}
],
resources: [

View file

@ -4,6 +4,6 @@
"defaultCommandTimeout": 20000,
"video": false,
"blacklistHosts": [
"*.google-analytics.com"
"*.usefathom.com"
]
}

View file

@ -1,26 +0,0 @@
// @flow
export const GA_TRACKING_ID = 'UA-31162386-5';
// https://developers.google.com/analytics/devguides/collection/gtagjs/pages
export const pageview = (url: string) => {
try {
window.gtag('config', GA_TRACKING_ID, {
page_location: url,
});
} catch (err) {
// dont crash the page if ga fails
}
};
// https://developers.google.com/analytics/devguides/collection/gtagjs/events
export const event = ({ action, category, label, value }: any) => {
try {
window.gtag('event', action, {
event_category: category,
event_label: label,
value,
});
} catch (err) {
// dont crash the page if ga fails
}
};

View file

@ -1 +1,11 @@
module.exports = {};
module.exports = {
target: 'serverless',
webpack: config => {
// Fixes npm packages that depend on `fs` module
config.node = {
fs: 'empty',
};
return config;
},
};

View file

@ -1,12 +1,4 @@
{
"alias": ["securitycheckli.st"],
"files": [
"components",
"config",
"lib",
"pages",
"static",
"types",
".babelrc"
]
"version": 2
}

11573
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -18,38 +18,38 @@
"lint:staged": "lint-staged"
},
"dependencies": {
"@sentry/browser": "^5.4.0",
"next": "^7.0.3",
"next-seo": "^1.11.2",
"react": "^16.8.0-alpha.0",
"react-clipboard.js": "^2.0.12",
"react-dom": "^16.8.0-alpha.0",
"react-markdown": "^4.0.8",
"styled-components": "^4.3.1",
"fathom-client": "^1.0.0",
"next": "^9.1.6",
"next-seo": "^3.2.0",
"react": "^16.12.0",
"react-clipboard.js": "^2.0.16",
"react-dom": "^16.12.0",
"react-markdown": "^4.2.2",
"styled-components": "^4.4.1",
"throttle-debounce": "^2.1.0"
},
"devDependencies": {
"@babel/core": "^7.4.5",
"@babel/plugin-transform-flow-strip-types": "^7.4.4",
"@babel/preset-flow": "^7.0.0",
"@babel/core": "^7.7.7",
"@babel/plugin-transform-flow-strip-types": "^7.7.4",
"@babel/preset-flow": "^7.7.4",
"@cypress/browserify-preprocessor": "^2.1.1",
"babel-eslint": "^10.0.1",
"babel-plugin-styled-components": "^1.10.0",
"babel-plugin-transform-define": "^1.3.1",
"cypress": "^3.3.1",
"eslint": "^5.16.0",
"eslint-config-airbnb": "^17.1.0",
"eslint-config-prettier": "^4.3.0",
"eslint-config-react-app": "^4.0.1",
"eslint-plugin-flowtype": "^3.9.1",
"eslint-plugin-import": "^2.17.3",
"eslint-plugin-jsx-a11y": "^6.2.1",
"eslint-plugin-prettier": "^3.1.0",
"eslint-plugin-react": "^7.13.0",
"flow-bin": "^0.95.1",
"lint-staged": "^8.2.0",
"prettier": "^1.18.2",
"prettier-eslint": "^8.8.2"
"babel-eslint": "^10.0.3",
"babel-plugin-styled-components": "^1.10.6",
"babel-plugin-transform-define": "^2.0.0",
"cypress": "^3.8.0",
"eslint": "^6.8.0",
"eslint-config-airbnb": "^18.0.1",
"eslint-config-prettier": "^6.8.0",
"eslint-config-react-app": "^5.0.1",
"eslint-plugin-flowtype": "^4.5.2",
"eslint-plugin-import": "^2.19.1",
"eslint-plugin-jsx-a11y": "^6.2.3",
"eslint-plugin-prettier": "^3.1.2",
"eslint-plugin-react": "^7.17.0",
"flow-bin": "^0.114.0",
"lint-staged": "^9.5.0",
"prettier": "^1.19.1",
"prettier-eslint": "^9.0.1"
},
"lint-staged": {
"*.js": [

View file

@ -1,143 +1,35 @@
// @flow
import App, { Container } from 'next/app';
import * as React from 'react';
import Head from 'next/head';
import * as Sentry from '@sentry/browser';
import NextSeo from 'next-seo';
import { GlobalStyles } from '../static/normalize';
import defaultSEO from '../config/next-seo.js';
import * as React from 'react'
import App from 'next/app';
import Fathom from 'fathom-client'
import Router from 'next/router'
import Providers from '../components/Providers';
const SENTRY_PUBLIC_DSN =
'https://42334f0365364b63bc57f4245d111b87@sentry.io/1370339';
Router.events.on('routeChangeComplete', () => {
Fathom.trackPageview()
})
class SecurityChecklistApp extends App {
constructor() {
super();
Sentry.init({ dsn: SENTRY_PUBLIC_DSN });
}
// $FlowFixMe
componentDidCatch(error: mixed, errorInfo: any) {
Sentry.configureScope(scope => {
Object.keys(errorInfo).forEach(key => {
scope.setExtra(key, errorInfo[key]);
});
});
Sentry.captureException(error);
// This is needed to render errors correctly in development / production
super.componentDidCatch(error, errorInfo);
}
componentDidMount() {
Sentry.init({
dsn: 'https://b92b29b696884e5798e161962eac36de@sentry.io/1318151',
});
}
function FathomWrapper(props) {
React.useEffect(() => {
if (process.env.NODE_ENV === 'production') {
Fathom.load();
Fathom.setSiteId('ESMHTGZE');
Fathom.trackPageview();
}
}, [])
return <div {...props} />
}
class MyApp extends App {
render() {
const { Component, pageProps } = this.props;
return (
<Container>
<GlobalStyles />
<Head>
<meta name="theme-color" content="#FFF" key="theme-color" />
<meta
name="description"
content="A checklist for staying safe on the internet"
/>
<link
rel="apple-touch-icon"
sizes="57x57"
href="/static/apple-icon-57x57.png"
/>
<link
rel="apple-touch-icon"
sizes="60x60"
href="/static/apple-icon-60x60.png"
/>
<link
rel="apple-touch-icon"
sizes="72x72"
href="/static/apple-icon-72x72.png"
/>
<link
rel="apple-touch-icon"
sizes="76x76"
href="/static/apple-icon-76x76.png"
/>
<link
rel="apple-touch-icon"
sizes="114x114"
href="/static/apple-icon-114x114.png"
/>
<link
rel="apple-touch-icon"
sizes="120x120"
href="/static/apple-icon-120x120.png"
/>
<link
rel="apple-touch-icon"
sizes="144x144"
href="/static/apple-icon-144x144.png"
/>
<link
rel="apple-touch-icon"
sizes="152x152"
href="/static/apple-icon-152x152.png"
/>
<link
rel="apple-touch-icon"
sizes="180x180"
href="/static/apple-icon-180x180.png"
/>
<link
rel="icon"
type="image/png"
sizes="192x192"
href="/static/android-icon-192x192.png"
/>
<link
rel="icon"
type="image/png"
sizes="32x32"
href="/static/favicon-32x32.png"
/>
<link
rel="icon"
type="image/png"
sizes="96x96"
href="/static/favicon-96x96.png"
/>
<link
rel="icon"
type="image/png"
sizes="16x16"
href="/static/favicon-16x16.png"
/>
<link rel="manifest" href="/static/manifest.json" />
<meta name="msapplication-TileImage" content="/ms-icon-144x144.png" />
<link rel="mask-icon" href="/static/pinned-tab.svg" color="#FFF" />
<meta name="msapplication-TileColor" content="#ffffff" />
<script
src="https://browser.sentry-cdn.com/4.2.4/bundle.min.js"
crossOrigin="anonymous"
/>
{this.props.styleTags}
</Head>
<NextSeo config={defaultSEO} />
<Component {...pageProps} />
</Container>
<FathomWrapper>
<Providers>
<Component {...pageProps} />
</Providers>
</FathomWrapper>
);
}
}
export default SecurityChecklistApp;
export default MyApp;

View file

@ -2,7 +2,6 @@
import * as React from 'react';
import Document, { Head, Main, NextScript } from 'next/document';
import { ServerStyleSheet } from 'styled-components';
import { GA_TRACKING_ID } from '../lib/gtag';
export default class MyDocument extends Document {
// $FlowFixMe
@ -48,22 +47,6 @@ export default class MyDocument extends Document {
<body>
<Main />
<NextScript />
{/* Global Site Tag (gtag.js) - Google Analytics */}
<script
async
src={`https://www.googletagmanager.com/gtag/js?id=${GA_TRACKING_ID}`}
/>
<script
// eslint-disable-next-line
dangerouslySetInnerHTML={{
__html: `
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', '${GA_TRACKING_ID}');
`,
}}
/>
</body>
</html>
);

View file

@ -1,18 +1,8 @@
// @flow
import * as React from 'react';
import type { GetInitialProps } from '../types';
import Home from './index';
class Error extends React.Component<{}> {
static async getInitialProps({ res }: GetInitialProps) {
if (res && res.setHeader) {
const cacheAge = 60 * 60 * 24 * 30;
res.setHeader('Cache-Control', `public,s-maxage=${cacheAge}`);
}
return {};
}
render() {
return <Home />;
}

View file

@ -1,6 +1,6 @@
// @flow
import * as React from 'react';
import NextSeo from 'next-seo';
import { NextSeo } from 'next-seo';
import Page, { SectionHeading, Heading, Subheading } from '../components/Page';
export default function About() {

View file

@ -1,25 +1,14 @@
// @flow
import * as React from 'react';
import Page, { SectionHeading, Heading, Subheading } from '../components/Page';
import type { GetInitialProps } from '../types';
import Checklist from '../components/Checklist';
import ShareButtons from '../components/ShareButtons';
import BottomShare from '../components/BottomShare';
class Index extends React.Component<{}> {
static async getInitialProps({ res }: GetInitialProps) {
if (res && res.setHeader) {
// cache podcasts for a month
const cacheAge = 60 * 60 * 24 * 30;
res.setHeader('Cache-Control', `public,s-maxage=${cacheAge}`);
}
return {};
}
render() {
return (
<Page displayProgress={true}>
<Page displayProgress>
<SectionHeading>
<Heading>Be safe on the internet.</Heading>
<Subheading>

BIN
static/img/guardian.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

BIN
static/img/jumbo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

8868
yarn.lock Normal file

File diff suppressed because it is too large Load diff