Add cache-first service worker
This commit is contained in:
parent
b2b5f82486
commit
ca222ff10d
File diff suppressed because one or more lines are too long
@ -54,13 +54,13 @@
|
||||
"webpack": "^4.23.1",
|
||||
"webpack-dev-middleware": "^3.4.0",
|
||||
"webpack-hot-middleware": "^2.24.3",
|
||||
"webpack-manifest-plugin": "^2.0.4"
|
||||
"webpack-manifest-plugin": "^2.0.4",
|
||||
"workbox-webpack-plugin": "^3.6.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"autolinker": "^1.7.1",
|
||||
"backo": "^1.1.0",
|
||||
"classnames": "^2.2.6",
|
||||
"es6-promise": "^4.2.5",
|
||||
"fontfaceobserver": "^2.0.9",
|
||||
"formik": "^1.3.1",
|
||||
"history": "4.5.1",
|
||||
|
@ -186,11 +186,14 @@ i[class*=' icon-']:before {
|
||||
.app-info {
|
||||
width: 100%;
|
||||
font-family: Montserrat, sans-serif;
|
||||
background: #f6546a;
|
||||
background: #6bb758;
|
||||
color: #fff;
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
text-align: center;
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
.app-info-error {
|
||||
background: #f6546a;
|
||||
}
|
||||
|
||||
.app-container {
|
||||
@ -800,10 +803,6 @@ input.message-input-nick.invalid {
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
.app-info {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.tablist {
|
||||
width: 200px;
|
||||
transform: translateX(-200px);
|
||||
|
14
client/src/js/boot.js
Normal file
14
client/src/js/boot.js
Normal file
@ -0,0 +1,14 @@
|
||||
/* eslint-disable no-underscore-dangle */
|
||||
|
||||
// This entrypoint gets inlined in the index page cached by service workers
|
||||
// and is responsible for fetching the data we would otherwise embed
|
||||
|
||||
window.__env__ = fetch('/data', {
|
||||
credentials: 'same-origin'
|
||||
}).then(res => {
|
||||
if (res.ok) {
|
||||
return res.json();
|
||||
}
|
||||
|
||||
throw new Error(res.statusText);
|
||||
});
|
@ -1,7 +1,8 @@
|
||||
import React, { Suspense, lazy } from 'react';
|
||||
import Route from 'containers/Route';
|
||||
import AppInfo from 'components/AppInfo';
|
||||
import TabList from 'components/TabList';
|
||||
import classnames from 'classnames';
|
||||
import cn from 'classnames';
|
||||
|
||||
const Chat = lazy(() => import('containers/Chat'));
|
||||
const Connect = lazy(() => import('containers/Connect'));
|
||||
@ -16,9 +17,10 @@ const App = ({
|
||||
showTabList,
|
||||
select,
|
||||
push,
|
||||
hideMenu
|
||||
hideMenu,
|
||||
newVersionAvailable
|
||||
}) => {
|
||||
const mainClass = classnames('main-container', {
|
||||
const mainClass = cn('main-container', {
|
||||
'off-canvas': showTabList
|
||||
});
|
||||
|
||||
@ -31,9 +33,15 @@ const App = ({
|
||||
return (
|
||||
<div className="wrap" onClick={handleClick}>
|
||||
{!connected && (
|
||||
<div className="app-info">
|
||||
<AppInfo type="error">
|
||||
Connection lost, attempting to reconnect...
|
||||
</div>
|
||||
</AppInfo>
|
||||
)}
|
||||
{newVersionAvailable && (
|
||||
<AppInfo dismissible>
|
||||
A new version of dispatch just got installed, reload to start using
|
||||
it!
|
||||
</AppInfo>
|
||||
)}
|
||||
<div className="app-container">
|
||||
<TabList
|
||||
|
28
client/src/js/components/AppInfo.js
Normal file
28
client/src/js/components/AppInfo.js
Normal file
@ -0,0 +1,28 @@
|
||||
import React, { useState } from 'react';
|
||||
import cn from 'classnames';
|
||||
|
||||
const AppInfo = ({ type, children, dismissible }) => {
|
||||
const [dismissed, setDismissed] = useState(false);
|
||||
|
||||
if (!dismissed) {
|
||||
const handleDismiss = () => {
|
||||
if (dismissible) {
|
||||
setDismissed(true);
|
||||
}
|
||||
};
|
||||
|
||||
const className = cn('app-info', {
|
||||
[`app-info-${type}`]: type
|
||||
});
|
||||
|
||||
return (
|
||||
<div className={className} onClick={handleDismiss}>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
export default AppInfo;
|
@ -102,6 +102,7 @@ class Connect extends Component {
|
||||
}
|
||||
|
||||
export default withFormik({
|
||||
enableReinitialize: true,
|
||||
mapPropsToValues: ({ defaults }) => {
|
||||
let port = 6667;
|
||||
if (defaults.port) {
|
||||
|
@ -15,7 +15,8 @@ const mapState = createStructuredSelector({
|
||||
privateChats: getPrivateChats,
|
||||
servers: getServers,
|
||||
showTabList: getShowTabList,
|
||||
tab: getSelectedTab
|
||||
tab: getSelectedTab,
|
||||
newVersionAvailable: state => state.app.newVersionAvailable
|
||||
});
|
||||
|
||||
const mapDispatch = { push, select, hideMenu };
|
||||
|
@ -1,14 +1,14 @@
|
||||
//import 'es6-promise/auto';
|
||||
//import 'utils/ie11';
|
||||
import React from 'react';
|
||||
import { render } from 'react-dom';
|
||||
|
||||
import Root from 'components/Root';
|
||||
import { appSet } from 'state/app';
|
||||
import initRouter from 'utils/router';
|
||||
import Socket from 'utils/Socket';
|
||||
import configureStore from './store';
|
||||
import routes from './routes';
|
||||
import runModules from './modules';
|
||||
import { register } from './serviceWorker';
|
||||
import '../css/fonts.css';
|
||||
import '../css/fontello.css';
|
||||
import '../css/style.css';
|
||||
@ -24,3 +24,7 @@ initRouter(routes, store);
|
||||
runModules({ store, socket });
|
||||
|
||||
render(<Root store={store} />, document.getElementById('root'));
|
||||
|
||||
register({
|
||||
onUpdate: () => store.dispatch(appSet('newVersionAvailable', true))
|
||||
});
|
||||
|
@ -1,3 +1,4 @@
|
||||
/* eslint-disable no-underscore-dangle */
|
||||
import Cookie from 'js-cookie';
|
||||
import { socket as socketActions } from 'state/actions';
|
||||
import { getWrapWidth, setConnectDefaults, appSet } from 'state/app';
|
||||
@ -8,9 +9,7 @@ import { find } from 'utils';
|
||||
import { when } from 'utils/observe';
|
||||
import { replace } from 'utils/router';
|
||||
|
||||
export default function initialState({ store }) {
|
||||
const env = JSON.parse(document.getElementById('env').innerHTML);
|
||||
|
||||
function loadState({ store }, env) {
|
||||
store.dispatch(setConnectDefaults(env.defaults));
|
||||
store.dispatch(appSet('hexIP', env.hexIP));
|
||||
store.dispatch(setSettings(env.settings, true));
|
||||
@ -70,3 +69,12 @@ export default function initialState({ store }) {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export default function initialState(ctx) {
|
||||
if (window.__env__) {
|
||||
window.__env__.then(env => loadState(ctx, env));
|
||||
} else {
|
||||
const env = JSON.parse(document.getElementById('env').innerHTML);
|
||||
loadState(ctx, env);
|
||||
}
|
||||
}
|
||||
|
90
client/src/js/serviceWorker.js
Normal file
90
client/src/js/serviceWorker.js
Normal file
@ -0,0 +1,90 @@
|
||||
const isLocalhost = Boolean(
|
||||
window.location.hostname === 'localhost' ||
|
||||
// [::1] is the IPv6 localhost address.
|
||||
window.location.hostname === '[::1]' ||
|
||||
// 127.0.0.1/8 is considered localhost for IPv4.
|
||||
window.location.hostname.match(
|
||||
/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
|
||||
)
|
||||
);
|
||||
|
||||
function registerValidSW(swUrl, config) {
|
||||
navigator.serviceWorker
|
||||
.register(swUrl)
|
||||
.then(registration => {
|
||||
registration.onupdatefound = () => {
|
||||
const installingWorker = registration.installing;
|
||||
if (installingWorker == null) {
|
||||
return;
|
||||
}
|
||||
installingWorker.onstatechange = () => {
|
||||
if (installingWorker.state === 'installed') {
|
||||
if (navigator.serviceWorker.controller) {
|
||||
if (config && config.onUpdate) {
|
||||
config.onUpdate(registration);
|
||||
}
|
||||
} else {
|
||||
if (config && config.onSuccess) {
|
||||
config.onSuccess(registration);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error during service worker registration:', error);
|
||||
});
|
||||
}
|
||||
|
||||
function checkValidServiceWorker(swUrl, config) {
|
||||
// Check if the service worker can be found. If it can't reload the page.
|
||||
fetch(swUrl)
|
||||
.then(response => {
|
||||
// Ensure service worker exists, and that we really are getting a JS file.
|
||||
const contentType = response.headers.get('content-type');
|
||||
if (
|
||||
response.status === 404 ||
|
||||
(contentType != null && contentType.indexOf('javascript') === -1)
|
||||
) {
|
||||
// No service worker found. Probably a different app. Reload the page.
|
||||
navigator.serviceWorker.ready.then(registration => {
|
||||
registration.unregister().then(() => {
|
||||
window.location.reload();
|
||||
});
|
||||
});
|
||||
} else {
|
||||
// Service worker found. Proceed as normal.
|
||||
registerValidSW(swUrl, config);
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
console.log(
|
||||
'No internet connection found. App is running in offline mode.'
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export function register(config) {
|
||||
if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
|
||||
window.addEventListener('load', () => {
|
||||
const swUrl = '/sw.js';
|
||||
|
||||
if (isLocalhost) {
|
||||
// This is running on localhost. Let's check if a service worker still exists or not.
|
||||
checkValidServiceWorker(swUrl, config);
|
||||
} else {
|
||||
// Is not localhost. Just register service worker
|
||||
registerValidSW(swUrl, config);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function unregister() {
|
||||
if ('serviceWorker' in navigator) {
|
||||
navigator.serviceWorker.ready.then(registration => {
|
||||
registration.unregister();
|
||||
});
|
||||
}
|
||||
}
|
@ -22,7 +22,8 @@ const initialState = {
|
||||
readonly: false,
|
||||
showDetails: false
|
||||
},
|
||||
hexIP: false
|
||||
hexIP: false,
|
||||
newVersionAvailable: false
|
||||
};
|
||||
|
||||
export default createReducer(initialState, {
|
||||
|
6
client/src/js/sw.js
Normal file
6
client/src/js/sw.js
Normal file
@ -0,0 +1,6 @@
|
||||
workbox.skipWaiting();
|
||||
workbox.clientsClaim();
|
||||
|
||||
workbox.precaching.precacheAndRoute(self.__precacheManifest, {
|
||||
ignoreUrlParametersMatching: [/.*/]
|
||||
});
|
@ -1,12 +0,0 @@
|
||||
if (Object.keys) {
|
||||
try {
|
||||
Object.keys('');
|
||||
} catch (e) {
|
||||
Object.keys = function keys(o, k, r) {
|
||||
r = [];
|
||||
// eslint-disable-next-line
|
||||
for (k in o) r.hasOwnProperty.call(o, k) && r.push(k);
|
||||
return r;
|
||||
};
|
||||
}
|
||||
}
|
@ -4,10 +4,14 @@ var postcssPresetEnv = require('postcss-preset-env');
|
||||
var cssnano = require('cssnano');
|
||||
var TerserPlugin = require('terser-webpack-plugin');
|
||||
var ManifestPlugin = require('webpack-manifest-plugin');
|
||||
var { InjectManifest } = require('workbox-webpack-plugin');
|
||||
|
||||
module.exports = {
|
||||
mode: 'production',
|
||||
entry: ['./src/js/index'],
|
||||
entry: {
|
||||
main: './src/js/index',
|
||||
boot: './src/js/boot'
|
||||
},
|
||||
output: {
|
||||
filename: '[name].[chunkhash:8].js',
|
||||
chunkFilename: '[name].[chunkhash:8].js'
|
||||
@ -76,6 +80,11 @@ module.exports = {
|
||||
}),
|
||||
new ManifestPlugin({
|
||||
fileName: 'asset-manifest.json'
|
||||
}),
|
||||
new InjectManifest({
|
||||
swSrc: './src/js/sw.js',
|
||||
globDirectory: './src',
|
||||
globPatterns: ['font/*.woff2']
|
||||
})
|
||||
],
|
||||
optimization: {
|
||||
@ -89,6 +98,6 @@ module.exports = {
|
||||
}
|
||||
}
|
||||
},
|
||||
runtimeChunk: true
|
||||
runtimeChunk: 'single'
|
||||
}
|
||||
};
|
||||
|
234
client/yarn.lock
234
client/yarn.lock
@ -1489,6 +1489,13 @@ babel-eslint@^10.0.1:
|
||||
eslint-scope "3.7.1"
|
||||
eslint-visitor-keys "^1.0.0"
|
||||
|
||||
babel-extract-comments@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/babel-extract-comments/-/babel-extract-comments-1.0.0.tgz#0a2aedf81417ed391b85e18b4614e693a0351a21"
|
||||
integrity sha512-qWWzi4TlddohA91bFwgt6zO/J0X+io7Qp184Fw0m2JYRSTZnJbFR8+07KmzudHCZgOiKRCrjhylwv9Xd8gfhVQ==
|
||||
dependencies:
|
||||
babylon "^6.18.0"
|
||||
|
||||
babel-generator@^6.18.0, babel-generator@^6.26.0:
|
||||
version "6.26.1"
|
||||
resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.26.1.tgz#1844408d3b8f0d35a404ea7ac180f087a601bd90"
|
||||
@ -1551,11 +1558,19 @@ babel-plugin-jest-hoist@^23.2.0:
|
||||
resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-23.2.0.tgz#e61fae05a1ca8801aadee57a6d66b8cefaf44167"
|
||||
integrity sha1-5h+uBaHKiAGq3uV6bWa4zvr0QWc=
|
||||
|
||||
babel-plugin-syntax-object-rest-spread@^6.13.0:
|
||||
babel-plugin-syntax-object-rest-spread@^6.13.0, babel-plugin-syntax-object-rest-spread@^6.8.0:
|
||||
version "6.13.0"
|
||||
resolved "https://registry.yarnpkg.com/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz#fd6536f2bce13836ffa3a5458c4903a597bb3bf5"
|
||||
integrity sha1-/WU28rzhODb/o6VFjEkDpZe7O/U=
|
||||
|
||||
babel-plugin-transform-object-rest-spread@^6.26.0:
|
||||
version "6.26.0"
|
||||
resolved "https://registry.yarnpkg.com/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.26.0.tgz#0f36692d50fef6b7e2d4b3ac1478137a963b7b06"
|
||||
integrity sha1-DzZpLVD+9rfi1LOsFHgTepY7ewY=
|
||||
dependencies:
|
||||
babel-plugin-syntax-object-rest-spread "^6.8.0"
|
||||
babel-runtime "^6.26.0"
|
||||
|
||||
babel-preset-jest@^23.2.0:
|
||||
version "23.2.0"
|
||||
resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-23.2.0.tgz#8ec7a03a138f001a1a8fb1e8113652bf1a55da46"
|
||||
@ -2365,6 +2380,11 @@ commander@~2.17.1:
|
||||
resolved "https://registry.yarnpkg.com/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf"
|
||||
integrity sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==
|
||||
|
||||
common-tags@^1.4.0:
|
||||
version "1.8.0"
|
||||
resolved "https://registry.yarnpkg.com/common-tags/-/common-tags-1.8.0.tgz#8e3153e542d4a39e9b10554434afaaf98956a937"
|
||||
integrity sha512-6P6g0uetGpW/sdyUy/iQQCbFF0kWVMSIVSyYz7Zgjcgh8mgw8PQzDNZeyZ5DQ2gM7LBoZPHmnjz8rUthkBG5tw==
|
||||
|
||||
commondir@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b"
|
||||
@ -3267,11 +3287,6 @@ es6-promise@^4.1.1:
|
||||
resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.4.tgz#dc4221c2b16518760bd8c39a52d8f356fc00ed29"
|
||||
integrity sha512-/NdNZVJg+uZgtm9eS3O6lrOLYmQag2DjdEXuPaHlZ6RuVqgqaVZfgYCepEIKsLqwdQArOPtC3XzRLqGGfT8KQQ==
|
||||
|
||||
es6-promise@^4.2.5:
|
||||
version "4.2.5"
|
||||
resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.5.tgz#da6d0d5692efb461e082c14817fe2427d8f5d054"
|
||||
integrity sha512-n6wvpdE43VFtJq+lUDYDBFUwV8TZbuGXLV4D6wKafg13ldznKsyEvatubnmUe31zcvelSzOHF+XbaT+Bl9ObDg==
|
||||
|
||||
es6-symbol@^3.1.1, es6-symbol@~3.1.1:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.1.tgz#bf00ef4fdab6ba1b46ecb7b629b4c7ed5715cc77"
|
||||
@ -4043,6 +4058,15 @@ from2@^2.1.0:
|
||||
inherits "^2.0.1"
|
||||
readable-stream "^2.0.0"
|
||||
|
||||
fs-extra@^4.0.2:
|
||||
version "4.0.3"
|
||||
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-4.0.3.tgz#0d852122e5bc5beb453fb028e9c0c9bf36340c94"
|
||||
integrity sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==
|
||||
dependencies:
|
||||
graceful-fs "^4.1.2"
|
||||
jsonfile "^4.0.0"
|
||||
universalify "^0.1.0"
|
||||
|
||||
fs-extra@^7.0.0:
|
||||
version "7.0.0"
|
||||
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.0.tgz#8cc3f47ce07ef7b3593a11b9fb245f7e34c041d6"
|
||||
@ -4146,6 +4170,11 @@ get-caller-file@^1.0.1:
|
||||
resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5"
|
||||
integrity sha1-9wLmMSfn4jHBYKgMFVSstw1QR+U=
|
||||
|
||||
get-own-enumerable-property-symbols@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.0.tgz#b877b49a5c16aefac3655f2ed2ea5b684df8d203"
|
||||
integrity sha512-CIJYJC4GGF06TakLg8z4GQKvDsx9EMspVxOYih7LerEL/WosUnFIww45CGfxfeKHqlg3twgUrYRT1O3WQqjGCg==
|
||||
|
||||
get-stdin@^6.0.0:
|
||||
version "6.0.0"
|
||||
resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-6.0.0.tgz#9e09bf712b360ab9225e812048f71fde9c89657b"
|
||||
@ -5070,7 +5099,7 @@ is-number@^4.0.0:
|
||||
resolved "https://registry.yarnpkg.com/is-number/-/is-number-4.0.0.tgz#0026e37f5454d73e356dfe6564699867c6a7f0ff"
|
||||
integrity sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==
|
||||
|
||||
is-obj@^1.0.0:
|
||||
is-obj@^1.0.0, is-obj@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f"
|
||||
integrity sha1-PkcprB9f3gJc19g6iW2rn09n2w8=
|
||||
@ -5123,6 +5152,11 @@ is-regex@^1.0.4:
|
||||
dependencies:
|
||||
has "^1.0.1"
|
||||
|
||||
is-regexp@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/is-regexp/-/is-regexp-1.0.0.tgz#fd2d883545c46bac5a633e7b9a09e87fa2cb5069"
|
||||
integrity sha1-/S2INUXEa6xaYz57mgnof6LLUGk=
|
||||
|
||||
is-relative@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/is-relative/-/is-relative-1.0.0.tgz#a1bb6935ce8c5dba1e8b9754b9b2dcc020e2260d"
|
||||
@ -5189,6 +5223,13 @@ isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
|
||||
integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=
|
||||
|
||||
isemail@3.x.x:
|
||||
version "3.2.0"
|
||||
resolved "https://registry.yarnpkg.com/isemail/-/isemail-3.2.0.tgz#59310a021931a9fb06bbb51e155ce0b3f236832c"
|
||||
integrity sha512-zKqkK+O+dGqevc93KNsbZ/TqTUFd46MwWjYOoMrjIMZ51eU7DtQG3Wmd9SQQT7i7RVnuTPEiYEWHU3MSbxC1Tg==
|
||||
dependencies:
|
||||
punycode "2.x.x"
|
||||
|
||||
isexe@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
|
||||
@ -5607,6 +5648,15 @@ jest@^23.6.0:
|
||||
import-local "^1.0.0"
|
||||
jest-cli "^23.6.0"
|
||||
|
||||
joi@^11.1.1:
|
||||
version "11.4.0"
|
||||
resolved "https://registry.yarnpkg.com/joi/-/joi-11.4.0.tgz#f674897537b625e9ac3d0b7e1604c828ad913ccb"
|
||||
integrity sha512-O7Uw+w/zEWgbL6OcHbyACKSj0PkQeUgmehdoXVSxt92QFCq4+1390Rwh5moI2K/OgC7D8RHRZqHZxT2husMJHA==
|
||||
dependencies:
|
||||
hoek "4.x.x"
|
||||
isemail "3.x.x"
|
||||
topo "2.x.x"
|
||||
|
||||
js-cookie@^2.1.4:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-2.2.0.tgz#1b2c279a6eece380a12168b92485265b35b1effb"
|
||||
@ -6044,7 +6094,7 @@ lodash.template@^3.0.0:
|
||||
lodash.restparam "^3.0.0"
|
||||
lodash.templatesettings "^3.0.0"
|
||||
|
||||
lodash.template@^4.2.4:
|
||||
lodash.template@^4.2.4, lodash.template@^4.4.0:
|
||||
version "4.4.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-4.4.0.tgz#e73a0385c8355591746e020b99679c690e68fba0"
|
||||
integrity sha1-5zoDhcg1VZF0bgILmWecaQ5o+6A=
|
||||
@ -7877,6 +7927,11 @@ prettier@1.14.3:
|
||||
resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.14.3.tgz#90238dd4c0684b7edce5f83b0fb7328e48bd0895"
|
||||
integrity sha512-qZDVnCrnpsRJJq5nSsiHCE3BYMED2OtsI+cmzIzF1QIfqm5ALf8tEJcO27zV1gKNKRPdhjO0dNWnrzssDQ1tFg==
|
||||
|
||||
pretty-bytes@^4.0.2:
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-4.0.2.tgz#b2bf82e7350d65c6c33aa95aaa5a4f6327f61cd9"
|
||||
integrity sha1-sr+C5zUNZcbDOqlaqlpPYyf2HNk=
|
||||
|
||||
pretty-format@^23.6.0:
|
||||
version "23.6.0"
|
||||
resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-23.6.0.tgz#5eaac8eeb6b33b987b7fe6097ea6a8a146ab5760"
|
||||
@ -8017,16 +8072,16 @@ punycode@1.3.2:
|
||||
resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d"
|
||||
integrity sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=
|
||||
|
||||
punycode@2.x.x, punycode@^2.1.0:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
|
||||
integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
|
||||
|
||||
punycode@^1.2.4, punycode@^1.4.1:
|
||||
version "1.4.1"
|
||||
resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
|
||||
integrity sha1-wNWmOycYgArY4esPpSachN1BhF4=
|
||||
|
||||
punycode@^2.1.0:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
|
||||
integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
|
||||
|
||||
q@^1.1.2:
|
||||
version "1.5.1"
|
||||
resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7"
|
||||
@ -8170,7 +8225,7 @@ react-redux@^5.1.0:
|
||||
react-is "^16.6.0"
|
||||
react-lifecycles-compat "^3.0.0"
|
||||
|
||||
react-test-renderer@16.7.0-alpha.0:
|
||||
react-test-renderer@^16.7.0-alpha.0:
|
||||
version "16.7.0-alpha.0"
|
||||
resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-16.7.0-alpha.0.tgz#f60e888621537cf8301fc154e8e98e59fb9c7050"
|
||||
integrity sha512-yOJTaUgy7V/Lpmv61g2oJdwEGUiAVJ21mYlHtUniUC8rW0HVpTVMDAVSEqgjlCYDfTwGh3hNTvoYaODJzkQKMw==
|
||||
@ -9210,6 +9265,15 @@ string_decoder@~0.10.x:
|
||||
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94"
|
||||
integrity sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=
|
||||
|
||||
stringify-object@^3.2.2:
|
||||
version "3.3.0"
|
||||
resolved "https://registry.yarnpkg.com/stringify-object/-/stringify-object-3.3.0.tgz#703065aefca19300d3ce88af4f5b3956d7556629"
|
||||
integrity sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==
|
||||
dependencies:
|
||||
get-own-enumerable-property-symbols "^3.0.0"
|
||||
is-obj "^1.0.1"
|
||||
is-regexp "^1.0.0"
|
||||
|
||||
stringstream@~0.0.4, stringstream@~0.0.5:
|
||||
version "0.0.5"
|
||||
resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878"
|
||||
@ -9241,6 +9305,14 @@ strip-bom@^2.0.0:
|
||||
dependencies:
|
||||
is-utf8 "^0.2.0"
|
||||
|
||||
strip-comments@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/strip-comments/-/strip-comments-1.0.2.tgz#82b9c45e7f05873bee53f37168af930aa368679d"
|
||||
integrity sha512-kL97alc47hoyIQSV165tTt9rG5dn4w1dNnBhOQ3bOU1Nc1hel09jnXANaHJ7vzHLd4Ju8kseDGzlev96pghLFw==
|
||||
dependencies:
|
||||
babel-extract-comments "^1.0.0"
|
||||
babel-plugin-transform-object-rest-spread "^6.26.0"
|
||||
|
||||
strip-eof@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf"
|
||||
@ -9537,6 +9609,13 @@ to-through@^2.0.0:
|
||||
dependencies:
|
||||
through2 "^2.0.3"
|
||||
|
||||
topo@2.x.x:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/topo/-/topo-2.0.2.tgz#cd5615752539057c0dc0491a621c3bc6fbe1d182"
|
||||
integrity sha1-zVYVdSU5BXwNwEkaYhw7xvvh0YI=
|
||||
dependencies:
|
||||
hoek "4.x.x"
|
||||
|
||||
tough-cookie@>=2.3.3, tough-cookie@^2.3.3, tough-cookie@~2.3.0, tough-cookie@~2.3.3:
|
||||
version "2.3.4"
|
||||
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.4.tgz#ec60cee38ac675063ffc97a5c18970578ee83655"
|
||||
@ -10154,6 +10233,133 @@ wordwrap@~1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb"
|
||||
integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=
|
||||
|
||||
workbox-background-sync@^3.6.3:
|
||||
version "3.6.3"
|
||||
resolved "https://registry.yarnpkg.com/workbox-background-sync/-/workbox-background-sync-3.6.3.tgz#6609a0fac9eda336a7c52e6aa227ba2ae532ad94"
|
||||
integrity sha512-ypLo0B6dces4gSpaslmDg5wuoUWrHHVJfFWwl1udvSylLdXvnrfhFfriCS42SNEe5lsZtcNZF27W/SMzBlva7Q==
|
||||
dependencies:
|
||||
workbox-core "^3.6.3"
|
||||
|
||||
workbox-broadcast-cache-update@^3.6.3:
|
||||
version "3.6.3"
|
||||
resolved "https://registry.yarnpkg.com/workbox-broadcast-cache-update/-/workbox-broadcast-cache-update-3.6.3.tgz#3f5dff22ada8c93e397fb38c1dc100606a7b92da"
|
||||
integrity sha512-pJl4lbClQcvp0SyTiEw0zLSsVYE1RDlCPtpKnpMjxFtu8lCFTAEuVyzxp9w7GF4/b3P4h5nyQ+q7V9mIR7YzGg==
|
||||
dependencies:
|
||||
workbox-core "^3.6.3"
|
||||
|
||||
workbox-build@^3.6.3:
|
||||
version "3.6.3"
|
||||
resolved "https://registry.yarnpkg.com/workbox-build/-/workbox-build-3.6.3.tgz#77110f9f52dc5d82fa6c1c384c6f5e2225adcbd8"
|
||||
integrity sha512-w0clZ/pVjL8VXy6GfthefxpEXs0T8uiRuopZSFVQ8ovfbH6c6kUpEh6DcYwm/Y6dyWPiCucdyAZotgjz+nRz8g==
|
||||
dependencies:
|
||||
babel-runtime "^6.26.0"
|
||||
common-tags "^1.4.0"
|
||||
fs-extra "^4.0.2"
|
||||
glob "^7.1.2"
|
||||
joi "^11.1.1"
|
||||
lodash.template "^4.4.0"
|
||||
pretty-bytes "^4.0.2"
|
||||
stringify-object "^3.2.2"
|
||||
strip-comments "^1.0.2"
|
||||
workbox-background-sync "^3.6.3"
|
||||
workbox-broadcast-cache-update "^3.6.3"
|
||||
workbox-cache-expiration "^3.6.3"
|
||||
workbox-cacheable-response "^3.6.3"
|
||||
workbox-core "^3.6.3"
|
||||
workbox-google-analytics "^3.6.3"
|
||||
workbox-navigation-preload "^3.6.3"
|
||||
workbox-precaching "^3.6.3"
|
||||
workbox-range-requests "^3.6.3"
|
||||
workbox-routing "^3.6.3"
|
||||
workbox-strategies "^3.6.3"
|
||||
workbox-streams "^3.6.3"
|
||||
workbox-sw "^3.6.3"
|
||||
|
||||
workbox-cache-expiration@^3.6.3:
|
||||
version "3.6.3"
|
||||
resolved "https://registry.yarnpkg.com/workbox-cache-expiration/-/workbox-cache-expiration-3.6.3.tgz#4819697254a72098a13f94b594325a28a1e90372"
|
||||
integrity sha512-+ECNph/6doYx89oopO/UolYdDmQtGUgo8KCgluwBF/RieyA1ZOFKfrSiNjztxOrGJoyBB7raTIOlEEwZ1LaHoA==
|
||||
dependencies:
|
||||
workbox-core "^3.6.3"
|
||||
|
||||
workbox-cacheable-response@^3.6.3:
|
||||
version "3.6.3"
|
||||
resolved "https://registry.yarnpkg.com/workbox-cacheable-response/-/workbox-cacheable-response-3.6.3.tgz#869f1a68fce9063f6869ddbf7fa0a2e0a868b3aa"
|
||||
integrity sha512-QpmbGA9SLcA7fklBLm06C4zFg577Dt8u3QgLM0eMnnbaVv3rhm4vbmDpBkyTqvgK/Ly8MBDQzlXDtUCswQwqqg==
|
||||
dependencies:
|
||||
workbox-core "^3.6.3"
|
||||
|
||||
workbox-core@^3.6.3:
|
||||
version "3.6.3"
|
||||
resolved "https://registry.yarnpkg.com/workbox-core/-/workbox-core-3.6.3.tgz#69abba70a4f3f2a5c059295a6f3b7c62bd00e15c"
|
||||
integrity sha512-cx9cx0nscPkIWs8Pt98HGrS9/aORuUcSkWjG25GqNWdvD/pSe7/5Oh3BKs0fC+rUshCiyLbxW54q0hA+GqZeSQ==
|
||||
|
||||
workbox-google-analytics@^3.6.3:
|
||||
version "3.6.3"
|
||||
resolved "https://registry.yarnpkg.com/workbox-google-analytics/-/workbox-google-analytics-3.6.3.tgz#99df2a3d70d6e91961e18a6752bac12e91fbf727"
|
||||
integrity sha512-RQBUo/6SXtIaQTRFj4RQZ9e1gAl7D8oS5S+Hi173Kk70/BgJjzPwXpC5A249Jv5YfkCOLMQCeF9A27BiD0b0ig==
|
||||
dependencies:
|
||||
workbox-background-sync "^3.6.3"
|
||||
workbox-core "^3.6.3"
|
||||
workbox-routing "^3.6.3"
|
||||
workbox-strategies "^3.6.3"
|
||||
|
||||
workbox-navigation-preload@^3.6.3:
|
||||
version "3.6.3"
|
||||
resolved "https://registry.yarnpkg.com/workbox-navigation-preload/-/workbox-navigation-preload-3.6.3.tgz#a2c34eb7c17e7485b795125091215f757b3c4964"
|
||||
integrity sha512-dd26xTX16DUu0i+MhqZK/jQXgfIitu0yATM4jhRXEmpMqQ4MxEeNvl2CgjDMOHBnCVMax+CFZQWwxMx/X/PqCw==
|
||||
dependencies:
|
||||
workbox-core "^3.6.3"
|
||||
|
||||
workbox-precaching@^3.6.3:
|
||||
version "3.6.3"
|
||||
resolved "https://registry.yarnpkg.com/workbox-precaching/-/workbox-precaching-3.6.3.tgz#5341515e9d5872c58ede026a31e19bafafa4e1c1"
|
||||
integrity sha512-aBqT66BuMFviPTW6IpccZZHzpA8xzvZU2OM1AdhmSlYDXOJyb1+Z6blVD7z2Q8VNtV1UVwQIdImIX+hH3C3PIw==
|
||||
dependencies:
|
||||
workbox-core "^3.6.3"
|
||||
|
||||
workbox-range-requests@^3.6.3:
|
||||
version "3.6.3"
|
||||
resolved "https://registry.yarnpkg.com/workbox-range-requests/-/workbox-range-requests-3.6.3.tgz#3cc21cba31f2dd8c43c52a196bcc8f6cdbcde803"
|
||||
integrity sha512-R+yLWQy7D9aRF9yJ3QzwYnGFnGDhMUij4jVBUVtkl67oaVoP1ymZ81AfCmfZro2kpPRI+vmNMfxxW531cqdx8A==
|
||||
dependencies:
|
||||
workbox-core "^3.6.3"
|
||||
|
||||
workbox-routing@^3.6.3:
|
||||
version "3.6.3"
|
||||
resolved "https://registry.yarnpkg.com/workbox-routing/-/workbox-routing-3.6.3.tgz#659cd8f9274986cfa98fda0d050de6422075acf7"
|
||||
integrity sha512-bX20i95OKXXQovXhFOViOK63HYmXvsIwZXKWbSpVeKToxMrp0G/6LZXnhg82ijj/S5yhKNRf9LeGDzaqxzAwMQ==
|
||||
dependencies:
|
||||
workbox-core "^3.6.3"
|
||||
|
||||
workbox-strategies@^3.6.3:
|
||||
version "3.6.3"
|
||||
resolved "https://registry.yarnpkg.com/workbox-strategies/-/workbox-strategies-3.6.3.tgz#11a0dc249a7bc23d3465ec1322d28fa6643d64a0"
|
||||
integrity sha512-Pg5eulqeKet2y8j73Yw6xTgLdElktcWExGkzDVCGqfV9JCvnGuEpz5eVsCIK70+k4oJcBCin9qEg3g3CwEIH3g==
|
||||
dependencies:
|
||||
workbox-core "^3.6.3"
|
||||
|
||||
workbox-streams@^3.6.3:
|
||||
version "3.6.3"
|
||||
resolved "https://registry.yarnpkg.com/workbox-streams/-/workbox-streams-3.6.3.tgz#beaea5d5b230239836cc327b07d471aa6101955a"
|
||||
integrity sha512-rqDuS4duj+3aZUYI1LsrD2t9hHOjwPqnUIfrXSOxSVjVn83W2MisDF2Bj+dFUZv4GalL9xqErcFW++9gH+Z27w==
|
||||
dependencies:
|
||||
workbox-core "^3.6.3"
|
||||
|
||||
workbox-sw@^3.6.3:
|
||||
version "3.6.3"
|
||||
resolved "https://registry.yarnpkg.com/workbox-sw/-/workbox-sw-3.6.3.tgz#278ea4c1831b92bbe2d420da8399176c4b2789ff"
|
||||
integrity sha512-IQOUi+RLhvYCiv80RP23KBW/NTtIvzvjex28B8NW1jOm+iV4VIu3VXKXTA6er5/wjjuhmtB28qEAUqADLAyOSg==
|
||||
|
||||
workbox-webpack-plugin@^3.6.3:
|
||||
version "3.6.3"
|
||||
resolved "https://registry.yarnpkg.com/workbox-webpack-plugin/-/workbox-webpack-plugin-3.6.3.tgz#a807bb891b4e4e3c808df07e58f17de2d5ba6182"
|
||||
integrity sha512-RwmKjc7HFHUFHoOlKoZUq9349u0QN3F8W5tZZU0vc1qsBZDINWXRiIBCAKvo/Njgay5sWz7z4I2adnyTo97qIQ==
|
||||
dependencies:
|
||||
babel-runtime "^6.26.0"
|
||||
json-stable-stringify "^1.0.1"
|
||||
workbox-build "^3.6.3"
|
||||
|
||||
worker-farm@^1.5.2:
|
||||
version "1.6.0"
|
||||
resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.6.0.tgz#aecc405976fab5a95526180846f0dba288f3a4a0"
|
||||
|
@ -21,6 +21,7 @@
|
||||
<% if cssPath != "" { %>
|
||||
<link href="/<%== cssPath %>" rel="stylesheet">
|
||||
<% } %>
|
||||
|
||||
<link rel="icon" href="data:;base64,=">
|
||||
|
||||
<script><%== inlineScript %></script>
|
||||
@ -28,7 +29,11 @@
|
||||
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
|
||||
<% if data != nil { %>
|
||||
<script id="env" type="application/json"><% easyjson.MarshalToWriter(data, w) %></script>
|
||||
<% } %>
|
||||
|
||||
<% for _, script := range scripts { %>
|
||||
<script src="/<%== script %>"></script>
|
||||
<% } %>
|
||||
|
@ -16,9 +16,12 @@ io.WriteString(w, "\" rel=\"stylesheet\">")
|
||||
}
|
||||
io.WriteString(w, "<link rel=\"icon\" href=\"data:;base64,=\"><script>")
|
||||
io.WriteString(w, inlineScript )
|
||||
io.WriteString(w, "</script></head><body><div id=\"root\"></div><script id=\"env\" type=\"application/json\">")
|
||||
io.WriteString(w, "</script></head><body><div id=\"root\"></div>")
|
||||
if data != nil {
|
||||
io.WriteString(w, "<script id=\"env\" type=\"application/json\">")
|
||||
easyjson.MarshalToWriter(data, w)
|
||||
io.WriteString(w, "</script>")
|
||||
}
|
||||
for _, script := range scripts {
|
||||
io.WriteString(w, "<script src=\"/")
|
||||
io.WriteString(w, script )
|
||||
|
@ -53,6 +53,9 @@ var (
|
||||
indexScripts []string
|
||||
inlineScript string
|
||||
inlineScriptSha256 string
|
||||
inlineScriptSW string
|
||||
inlineScriptSWSha256 string
|
||||
serviceWorker []byte
|
||||
|
||||
h2PushAssets []h2PushAsset
|
||||
h2PushCookieValue string
|
||||
@ -84,17 +87,21 @@ func (d *Dispatch) initFileServer() {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
runtime, err := assets.Asset(manifest["runtime~main.js"] + ".br")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
runtime = decompressAsset(runtime)
|
||||
bootloader := decompressedAsset(manifest["boot.js"])
|
||||
runtime := decompressedAsset(manifest["runtime.js"])
|
||||
|
||||
inlineScript = string(runtime)
|
||||
inlineScriptSW = string(bootloader) + string(runtime)
|
||||
|
||||
hash := sha256.New()
|
||||
hash.Write(runtime)
|
||||
inlineScriptSha256 = base64.StdEncoding.EncodeToString(hash.Sum(nil))
|
||||
|
||||
hash.Reset()
|
||||
hash.Write(bootloader)
|
||||
hash.Write(runtime)
|
||||
inlineScriptSWSha256 = base64.StdEncoding.EncodeToString(hash.Sum(nil))
|
||||
|
||||
indexStylesheet = manifest["main.css"]
|
||||
indexScripts = []string{
|
||||
manifest["vendors~main.js"],
|
||||
@ -111,7 +118,19 @@ func (d *Dispatch) initFileServer() {
|
||||
h2PushCookieValue += asset.hash
|
||||
}
|
||||
|
||||
ignoreAssets := []string{
|
||||
manifest["runtime.js"],
|
||||
manifest["boot.js"],
|
||||
"sw.js",
|
||||
}
|
||||
|
||||
for _, assetPath := range manifest {
|
||||
for _, ignored := range ignoreAssets {
|
||||
if assetPath == ignored {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
file := &File{
|
||||
Path: assetPath,
|
||||
Asset: assetPath + ".br",
|
||||
@ -153,6 +172,18 @@ func (d *Dispatch) initFileServer() {
|
||||
}
|
||||
}
|
||||
|
||||
serviceWorker = decompressedAsset("sw.js")
|
||||
hash.Reset()
|
||||
IndexTemplate(hash, nil, indexStylesheet, inlineScriptSW, indexScripts)
|
||||
indexHash := base64.StdEncoding.EncodeToString(hash.Sum(nil))
|
||||
|
||||
serviceWorker = append(serviceWorker, []byte(`
|
||||
workbox.precaching.precacheAndRoute([{
|
||||
revision: '`+indexHash+`',
|
||||
url: '/?sw'
|
||||
}]);
|
||||
workbox.routing.registerNavigationRoute('/?sw');`)...)
|
||||
|
||||
if viper.GetBool("https.hsts.enabled") && viper.GetBool("https.enabled") {
|
||||
hstsHeader = "max-age=" + viper.GetString("https.hsts.max_age")
|
||||
|
||||
@ -179,6 +210,14 @@ func decompressAsset(data []byte) []byte {
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
||||
func decompressedAsset(name string) []byte {
|
||||
asset, err := assets.Asset(name + ".br")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
return decompressAsset(asset)
|
||||
}
|
||||
|
||||
func gzipAsset(data []byte) []byte {
|
||||
br, err := brotli.NewReader(bytes.NewReader(data), nil)
|
||||
if err != nil {
|
||||
@ -202,6 +241,14 @@ func (d *Dispatch) serveFiles(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
if r.URL.Path == "/sw.js" {
|
||||
w.Header().Set("Cache-Control", disabledCacheControl)
|
||||
w.Header().Set("Content-Type", "text/javascript")
|
||||
w.Header().Set("Content-Length", strconv.Itoa(len(serviceWorker)))
|
||||
w.Write(serviceWorker)
|
||||
return
|
||||
}
|
||||
|
||||
for _, file := range files {
|
||||
if strings.HasSuffix(r.URL.Path, file.Path) {
|
||||
d.serveFile(w, r, file)
|
||||
@ -215,15 +262,22 @@ func (d *Dispatch) serveFiles(w http.ResponseWriter, r *http.Request) {
|
||||
func (d *Dispatch) serveIndex(w http.ResponseWriter, r *http.Request) {
|
||||
state := d.handleAuth(w, r, false)
|
||||
|
||||
_, sw := r.URL.Query()["sw"]
|
||||
|
||||
if cspEnabled {
|
||||
var connectSrc string
|
||||
var wsSrc string
|
||||
if r.TLS != nil {
|
||||
connectSrc = "wss://" + r.Host
|
||||
wsSrc = "wss://" + r.Host
|
||||
} else {
|
||||
connectSrc = "ws://" + r.Host
|
||||
wsSrc = "ws://" + r.Host
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Security-Policy", "default-src 'none'; script-src 'self' 'sha256-"+inlineScriptSha256+"'; style-src 'self' 'unsafe-inline'; font-src 'self'; img-src data:; connect-src "+connectSrc)
|
||||
inlineSha := inlineScriptSha256
|
||||
if sw {
|
||||
inlineSha = inlineScriptSWSha256
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Security-Policy", "default-src 'none'; script-src 'self' 'sha256-"+inlineSha+"'; style-src 'self' 'unsafe-inline'; font-src 'self'; img-src data:; connect-src 'self' "+wsSrc)
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "text/html")
|
||||
@ -266,14 +320,24 @@ func (d *Dispatch) serveIndex(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
var data *indexData
|
||||
if !sw {
|
||||
data = getIndexData(r, state)
|
||||
}
|
||||
|
||||
inline := inlineScript
|
||||
if sw {
|
||||
inline = inlineScriptSW
|
||||
}
|
||||
|
||||
if strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") {
|
||||
w.Header().Set("Content-Encoding", "gzip")
|
||||
|
||||
gzw := gzip.NewWriter(w)
|
||||
IndexTemplate(gzw, getIndexData(r, state), indexStylesheet, inlineScript, indexScripts)
|
||||
IndexTemplate(gzw, data, indexStylesheet, inline, indexScripts)
|
||||
gzw.Close()
|
||||
} else {
|
||||
IndexTemplate(w, getIndexData(r, state), indexStylesheet, inlineScript, indexScripts)
|
||||
IndexTemplate(w, data, indexStylesheet, inline, indexScripts)
|
||||
}
|
||||
}
|
||||
|
||||
@ -289,16 +353,6 @@ func setPushCookie(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
func (d *Dispatch) serveFile(w http.ResponseWriter, r *http.Request, file *File) {
|
||||
info, err := assets.AssetInfo(file.Asset)
|
||||
if err != nil {
|
||||
http.Error(w, "", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
if !modifiedSince(w, r, info.ModTime()) {
|
||||
return
|
||||
}
|
||||
|
||||
data, err := assets.Asset(file.Asset)
|
||||
if err != nil {
|
||||
http.Error(w, "", http.StatusInternalServerError)
|
||||
@ -334,15 +388,3 @@ func (d *Dispatch) serveFile(w http.ResponseWriter, r *http.Request, file *File)
|
||||
w.Write(buf)
|
||||
}
|
||||
}
|
||||
|
||||
func modifiedSince(w http.ResponseWriter, r *http.Request, modtime time.Time) bool {
|
||||
t, err := time.Parse(http.TimeFormat, r.Header.Get("If-Modified-Since"))
|
||||
|
||||
if err == nil && modtime.Before(t.Add(1*time.Second)) {
|
||||
w.WriteHeader(http.StatusNotModified)
|
||||
return false
|
||||
}
|
||||
|
||||
w.Header().Set("Last-Modified", modtime.UTC().Format(http.TimeFormat))
|
||||
return true
|
||||
}
|
||||
|
@ -10,11 +10,11 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/spf13/viper"
|
||||
|
||||
"github.com/khlieng/dispatch/pkg/letsencrypt"
|
||||
"github.com/khlieng/dispatch/pkg/session"
|
||||
"github.com/khlieng/dispatch/storage"
|
||||
"github.com/mailru/easyjson"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
var channelStore = storage.NewChannelStore()
|
||||
@ -181,6 +181,15 @@ func (d *Dispatch) serve(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
d.upgradeWS(w, r, state)
|
||||
} else if strings.HasPrefix(r.URL.Path, "/data") {
|
||||
state := d.handleAuth(w, r, true)
|
||||
if state == nil {
|
||||
log.Println("[Auth] No state")
|
||||
fail(w, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
easyjson.MarshalToHTTPResponseWriter(getIndexData(r, state), w)
|
||||
} else {
|
||||
d.serveFiles(w, r)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user