From 957599ae01687d6b3d02a3c34fdbe2ac6bd920f9 Mon Sep 17 00:00:00 2001 From: Anike Arni Date: Thu, 16 Feb 2017 18:51:26 -0200 Subject: [#907] Bundles login static files separately Due to conflicts with public and protected urls, login and interstitial files have to be on a different public url from inbox and resources that require login. Therefore, here, we delegate that logic to webpack. Now we have a '/public' url and a '/assets' url for those static assets. --- service/pixelated/resources/__init__.py | 11 ++- .../pixelated/resources/backup_account_resource.py | 4 +- service/pixelated/resources/login_resource.py | 10 +-- service/pixelated/resources/root_resource.py | 14 ++-- service/test/unit/resources/test_helpers.py | 7 ++ service/test/unit/resources/test_login_resource.py | 2 +- web-ui/app/index.html | 34 ++++---- web-ui/app/js/page/default.js | 2 +- web-ui/app/sandbox.html | 2 +- web-ui/app/scss/base/_fonts.scss | 23 +++--- web-ui/config/copy-webpack.js | 91 ---------------------- web-ui/config/protected-assets-webpack.js | 25 ++++++ web-ui/config/public-assets-webpack.js | 10 +++ web-ui/src/backup_account/backup_account.html | 2 +- web-ui/src/backup_account/page.js | 2 +- web-ui/src/common/footer/footer.js | 2 +- web-ui/src/common/header/header.js | 2 +- web-ui/src/i18n.js | 2 +- web-ui/src/interstitial/interstitial.html | 6 +- web-ui/src/login/login.css | 2 +- web-ui/src/login/login.html | 12 +-- web-ui/webpack.config.js | 63 ++++++++++----- web-ui/webpack.production.config.js | 68 ++++++++++------ web-ui/webpack.test.config.js | 1 - 24 files changed, 198 insertions(+), 199 deletions(-) delete mode 100644 web-ui/config/copy-webpack.js create mode 100644 web-ui/config/protected-assets-webpack.js create mode 100644 web-ui/config/public-assets-webpack.js diff --git a/service/pixelated/resources/__init__.py b/service/pixelated/resources/__init__.py index 6bac2f59..f5512644 100644 --- a/service/pixelated/resources/__init__.py +++ b/service/pixelated/resources/__init__.py @@ -57,12 +57,15 @@ def handle_error_deferred(e, request): request.finish() -def get_startup_folder(): - path = os.path.dirname(os.path.abspath(__file__)) - return os.path.join(path, '..', 'assets') +def get_protected_static_folder(): + return os.path.join(_get_static_folder(), 'protected') -def get_static_folder(): +def get_public_static_folder(): + return os.path.join(_get_static_folder(), 'public') + + +def _get_static_folder(): static_folder = os.path.abspath(os.path.join(os.path.abspath(__file__), "..", "..", "..", "..", "web-ui", "dist")) if not os.path.exists(static_folder): static_folder = os.path.join('/', 'usr', 'share', 'pixelated-user-agent') diff --git a/service/pixelated/resources/backup_account_resource.py b/service/pixelated/resources/backup_account_resource.py index 5d9cb032..f1eeee53 100644 --- a/service/pixelated/resources/backup_account_resource.py +++ b/service/pixelated/resources/backup_account_resource.py @@ -19,13 +19,13 @@ from xml.sax import SAXParseException from pixelated.resources import BaseResource from twisted.python.filepath import FilePath -from pixelated.resources import get_static_folder +from pixelated.resources import get_protected_static_folder from twisted.web.http import OK from twisted.web.template import Element, XMLFile, renderElement class BackupAccountPage(Element): - loader = XMLFile(FilePath(os.path.join(get_static_folder(), 'backup_account.html'))) + loader = XMLFile(FilePath(os.path.join(get_protected_static_folder(), 'backup_account.html'))) def __init__(self): super(BackupAccountPage, self).__init__() diff --git a/service/pixelated/resources/login_resource.py b/service/pixelated/resources/login_resource.py index 160f12bf..bb05489e 100644 --- a/service/pixelated/resources/login_resource.py +++ b/service/pixelated/resources/login_resource.py @@ -20,7 +20,7 @@ from xml.sax import SAXParseException from pixelated.authentication import Authenticator from pixelated.config.leap import BootstrapUserServices from pixelated.resources import BaseResource, UnAuthorizedResource, IPixelatedSession -from pixelated.resources import get_static_folder, respond_json +from pixelated.resources import get_public_static_folder, respond_json from twisted.cred.error import UnauthorizedLogin from twisted.internet import defer from twisted.logger import Logger @@ -45,7 +45,7 @@ def parse_accept_language(all_headers): class DisclaimerElement(Element): - loader = XMLFile(FilePath(os.path.join(get_static_folder(), '_login_disclaimer_banner.html'))) + loader = XMLFile(FilePath(os.path.join(get_public_static_folder(), '_login_disclaimer_banner.html'))) def __init__(self, banner): super(DisclaimerElement, self).__init__() @@ -68,7 +68,7 @@ class DisclaimerElement(Element): class LoginWebSite(Element): - loader = XMLFile(FilePath(os.path.join(get_static_folder(), 'login.html'))) + loader = XMLFile(FilePath(os.path.join(get_public_static_folder(), 'login.html'))) def __init__(self, error_msg=None, disclaimer_banner_file=None): super(LoginWebSite, self).__init__() @@ -96,8 +96,8 @@ class LoginResource(BaseResource): self._authenticator = authenticator or Authenticator(provider) self._bootstrap_user_services = BootstrapUserServices(services_factory, provider) - static_folder = get_static_folder() - self.putChild('assets', File(static_folder)) + static_folder = get_public_static_folder() + self.putChild('public', File(static_folder)) with open(os.path.join(static_folder, 'interstitial.html')) as f: self.interstitial = f.read() diff --git a/service/pixelated/resources/root_resource.py b/service/pixelated/resources/root_resource.py index 37a0013e..320a1204 100644 --- a/service/pixelated/resources/root_resource.py +++ b/service/pixelated/resources/root_resource.py @@ -20,7 +20,7 @@ from string import Template from pixelated.resources.users import UsersResource from pixelated.resources import BaseResource, UnAuthorizedResource, UnavailableResource -from pixelated.resources import get_static_folder +from pixelated.resources import get_public_static_folder, get_protected_static_folder from pixelated.resources.attachments_resource import AttachmentsResource from pixelated.resources.sandbox_resource import SandboxResource from pixelated.resources.backup_account_resource import BackupAccountResource @@ -51,16 +51,17 @@ MODE_RUNNING = 2 class RootResource(BaseResource): def __init__(self, services_factory): BaseResource.__init__(self, services_factory) - self._static_folder = get_static_folder() - self._html_template = open(os.path.join(self._static_folder, 'index.html')).read() + self._public_static_folder = get_public_static_folder() + self._protected_static_folder = get_protected_static_folder() + self._html_template = open(os.path.join(self._protected_static_folder, 'index.html')).read() self._services_factory = services_factory self._child_resources = ChildResourcesMap() - with open(os.path.join(self._static_folder, 'interstitial.html')) as f: + with open(os.path.join(self._public_static_folder, 'interstitial.html')) as f: self.interstitial = f.read() self._startup_mode() def _startup_mode(self): - self.putChild('assets', File(self._static_folder)) + self.putChild('public', File(self._public_static_folder)) self.putChild('status', LoginStatusResource(self._services_factory)) self._mode = MODE_STARTUP @@ -89,8 +90,9 @@ class RootResource(BaseResource): return csrf_input and csrf_input == xsrf_token def initialize(self, provider=None, disclaimer_banner=None, authenticator=None): + self._child_resources.add('assets', File(self._protected_static_folder)) self._child_resources.add('backup-account', BackupAccountResource(self._services_factory)) - self._child_resources.add('sandbox', SandboxResource(self._static_folder)) + self._child_resources.add('sandbox', SandboxResource(self._protected_static_folder)) self._child_resources.add('keys', KeysResource(self._services_factory)) self._child_resources.add(AttachmentsResource.BASE_URL, AttachmentsResource(self._services_factory)) self._child_resources.add('contacts', ContactsResource(self._services_factory)) diff --git a/service/test/unit/resources/test_helpers.py b/service/test/unit/resources/test_helpers.py index e21c5373..6c456f51 100644 --- a/service/test/unit/resources/test_helpers.py +++ b/service/test/unit/resources/test_helpers.py @@ -18,6 +18,7 @@ from twisted.trial import unittest import re from pixelated.resources import respond_json, respond_json_deferred +from pixelated.resources import get_public_static_folder, get_protected_static_folder from test.unit.resources import DummySite from twisted.web.test.requesthelper import DummyRequest @@ -44,3 +45,9 @@ class TestHelpers(unittest.TestCase): self.assertEqual(b"{\"test\": \"yep\"}", request.written[0]) self.assertEqual([b"application/json"], request.responseHeaders.getRawHeaders("Content-Type")) + + def test_getting_public_folder_returns_path(self): + self.assertIn('web-ui/dist/public', get_public_static_folder()) + + def test_getting_protected_folder_returns_path(self): + self.assertIn('web-ui/dist/protected', get_protected_static_folder()) diff --git a/service/test/unit/resources/test_login_resource.py b/service/test/unit/resources/test_login_resource.py index 29592c1d..bd0f9122 100644 --- a/service/test/unit/resources/test_login_resource.py +++ b/service/test/unit/resources/test_login_resource.py @@ -230,7 +230,7 @@ class TestLoginPOST(unittest.TestCase): def assert_interstitial_in_response(_): mock_authenticate.assert_called_once_with(self.username, self.password) - interstitial_js_in_template = '' + interstitial_js_in_template = '' self.assertIn(interstitial_js_in_template, self.request.written[0]) d.addCallback(assert_interstitial_in_response) diff --git a/web-ui/app/index.html b/web-ui/app/index.html index b40aecdf..72b04c83 100644 --- a/web-ui/app/index.html +++ b/web-ui/app/index.html @@ -1,15 +1,15 @@ - + $account_email - Pixelated Mail - - - + + + @@ -92,19 +92,19 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + diff --git a/web-ui/app/js/page/default.js b/web-ui/app/js/page/default.js index ecaedfd8..541bb4b7 100644 --- a/web-ui/app/js/page/default.js +++ b/web-ui/app/js/page/default.js @@ -96,7 +96,7 @@ define( 'use strict'; function initialize(path) { - viewI18n.init(path + '/assets/'); + viewI18n.init(path + '/public/'); viewI18n.loaded(function() { paneContractExpand.attachTo(document); diff --git a/web-ui/app/sandbox.html b/web-ui/app/sandbox.html index 3e110977..52da1f5b 100644 --- a/web-ui/app/sandbox.html +++ b/web-ui/app/sandbox.html @@ -6,7 +6,7 @@ - + diff --git a/web-ui/app/scss/base/_fonts.scss b/web-ui/app/scss/base/_fonts.scss index dfc56dd8..9a47b5ed 100644 --- a/web-ui/app/scss/base/_fonts.scss +++ b/web-ui/app/scss/base/_fonts.scss @@ -2,67 +2,66 @@ font-family: 'Open Sans'; font-style: normal; font-weight: 300; - src: local('Open Sans Light'), local('OpenSans-Light'), url('/assets/fonts/OpenSans-Light.woff') format('woff'); + src: local('Open Sans Light'), local('OpenSans-Light'), url('/public/fonts/OpenSans-Light.woff') format('woff'); } @font-face { font-family: 'Open Sans'; font-style: normal; font-weight: 400; - src: local('Open Sans'), local('OpenSans'), url('/assets/fonts/OpenSans.woff') format('woff'); + src: local('Open Sans'), local('OpenSans'), url('/public/fonts/OpenSans.woff') format('woff'); } @font-face { font-family: 'Open Sans'; font-style: normal; font-weight: 600; - src: local('Open Sans Semibold'), local('OpenSans-Semibold'), url('/assets/fonts/OpenSans-Semibold.woff') format('woff'); + src: local('Open Sans Semibold'), local('OpenSans-Semibold'), url('/public/fonts/OpenSans-Semibold.woff') format('woff'); } @font-face { font-family: 'Open Sans'; font-style: normal; font-weight: 700; - src: local('Open Sans Bold'), local('OpenSans-Bold'), url('/assets/fonts/OpenSans-Bold.woff') format('woff'); + src: local('Open Sans Bold'), local('OpenSans-Bold'), url('/public/fonts/OpenSans-Bold.woff') format('woff'); } @font-face { font-family: 'Open Sans'; font-style: normal; font-weight: 800; - src: local('Open Sans Extrabold'), local('OpenSans-Extrabold'), url('/assets/fonts/OpenSans-Extrabold.woff') format('woff'); + src: local('Open Sans Extrabold'), local('OpenSans-Extrabold'), url('/public/fonts/OpenSans-Extrabold.woff') format('woff'); } @font-face { font-family: 'Open Sans'; font-style: italic; font-weight: 300; - src: local('Open Sans Light Italic'), local('OpenSansLight-Italic'), url('/assets/fonts/OpenSansLight-Italic.woff') format('woff'); + src: local('Open Sans Light Italic'), local('OpenSansLight-Italic'), url('/public/fonts/OpenSansLight-Italic.woff') format('woff'); } @font-face { font-family: 'Open Sans'; font-style: italic; font-weight: 400; - src: local('Open Sans Italic'), local('OpenSans-Italic'), url('/assets/fonts/OpenSans-Italic.woff') format('woff'); + src: local('Open Sans Italic'), local('OpenSans-Italic'), url('/public/fonts/OpenSans-Italic.woff') format('woff'); } @font-face { font-family: 'Open Sans'; font-style: italic; font-weight: 600; - src: local('Open Sans Semibold Italic'), local('OpenSans-SemiboldItalic'), url('/assets/fonts/OpenSans-SemiboldItalic.woff') format('woff'); + src: local('Open Sans Semibold Italic'), local('OpenSans-SemiboldItalic'), url('/public/fonts/OpenSans-SemiboldItalic.woff') format('woff'); } @font-face { font-family: 'Open Sans'; font-style: italic; font-weight: 700; - src: local('Open Sans Bold Italic'), local('OpenSans-BoldItalic'), url('/assets/fonts/OpenSans-BoldItalic.woff') format('woff'); + src: local('Open Sans Bold Italic'), local('OpenSans-BoldItalic'), url('/public/fonts/OpenSans-BoldItalic.woff') format('woff'); } @font-face { font-family: 'Open Sans'; font-style: italic; font-weight: 800; - src: local('Open Sans Extrabold Italic'), local('OpenSans-ExtraboldItalic'), url('/assets/fonts/OpenSans-ExtraboldItalic.woff') format('woff'); + src: local('Open Sans Extrabold Italic'), local('OpenSans-ExtraboldItalic'), url('/public/fonts/OpenSans-ExtraboldItalic.woff') format('woff'); } @font-face { font-family: 'icomoon'; font-style: normal; font-weight: 400; - src: url('/assets/fonts/icomoon.woff') format('woff'), url('/assets/fonts/icomoon.ttf') format('truetype'), ; + src: url('/public/fonts/icomoon.woff') format('woff'), url('/public/fonts/icomoon.ttf') format('truetype'), ; } - diff --git a/web-ui/config/copy-webpack.js b/web-ui/config/copy-webpack.js deleted file mode 100644 index 7e56d760..00000000 --- a/web-ui/config/copy-webpack.js +++ /dev/null @@ -1,91 +0,0 @@ -var CopyWebpackPlugin = require('copy-webpack-plugin'); - -module.exports = new CopyWebpackPlugin([ - { context: 'app/', from: '404.html' }, - { context: 'app/', from: 'index.html' }, - { context: 'app/', from: 'sandbox.html' }, - { context: 'src/backup_account/', from: 'backup_account.html' }, - { context: 'src/login/', from: '*.html' }, - { context: 'src/login/', from: '*.css' }, - { context: 'src/interstitial/', from: '*' }, - { context: 'app/', from: 'css/*' }, - { context: 'app/', from: 'fonts/*' }, - { context: 'app/', from: 'locales/**/*' }, - { context: 'app/', from: 'images/**/*' }, - { context: 'app/', from: 'bower_components/font-awesome/fonts/*' }, - { - context: 'app/', - from: 'bower_components/font-awesome/css/font-awesome.min.css', - to: 'bower_components/font-awesome/css' - }, - { - context: 'app/', - from: 'bower_components/jquery-file-upload/css/jquery.fileupload.css', - to: 'bower_components/jquery-file-upload/css' - }, - { - context: 'app/', - from: 'bower_components/modernizr/modernizr.js', - to: 'bower_components/modernizr' - }, - { - context: 'app/', - from: 'bower_components/lodash/dist/lodash.min.js', - to: 'bower_components/lodash/dist' - }, - { - context: 'app/', - from: 'bower_components/jquery/dist/jquery.min.js', - to: 'bower_components/jquery/dist' - }, - { - context: 'app/', - from: 'bower_components/jquery-ui/jquery-ui.min.js', - to: 'bower_components/jquery-ui' - }, - { - context: 'app/', - from: 'bower_components/jquery-file-upload/js/jquery.fileupload.js', - to: 'bower_components/jquery-file-upload/js' - }, - { - context: 'app/', - from: 'bower_components/handlebars/handlebars.min.js', - to: 'bower_components/handlebars' - }, - { - context: 'app/', - from: 'bower_components/typeahead.js/dist/typeahead.bundle.min.js', - to: 'bower_components/typeahead.js/dist' - }, - { - context: 'app/', - from: 'bower_components/iframe-resizer/js/iframeResizer.min.js', - to: 'bower_components/iframe-resizer/js' - }, - { - context: 'app/', - from: 'bower_components/iframe-resizer/js/iframeResizer.contentWindow.min.js', - to: 'bower_components/iframe-resizer/js' - }, - { - context: 'app/', - from: 'bower_components/foundation/js/foundation.js', - to: 'bower_components/foundation/js' - }, - { - context: 'app/', - from: 'bower_components/foundation/js/foundation/foundation.reveal.js', - to: 'bower_components/foundation/js/foundation' - }, - { - context: 'app/', - from: 'bower_components/foundation/js/foundation/foundation.offcanvas.js', - to: 'bower_components/foundation/js/foundation' - }, - { - context: 'app/', - from: 'js/foundation/initialize_foundation.js', - to: 'js/foundation' - } -]) diff --git a/web-ui/config/protected-assets-webpack.js b/web-ui/config/protected-assets-webpack.js new file mode 100644 index 00000000..85654cf0 --- /dev/null +++ b/web-ui/config/protected-assets-webpack.js @@ -0,0 +1,25 @@ +var CopyWebpackPlugin = require('copy-webpack-plugin'); + +module.exports = new CopyWebpackPlugin([ + { context: 'app/', from: '404.html' }, + { context: 'app/', from: 'index.html' }, + { context: 'app/', from: 'sandbox.html' }, + { context: 'app/', from: 'css/*' }, + { context: 'src/backup_account/', from: 'backup_account.html' }, + { context: 'app/bower_components/font-awesome/', from: 'fonts/*' }, + { context: 'app/bower_components/font-awesome/', from: 'css/font-awesome.min.css', to: 'css' }, + { context: 'app/bower_components/jquery-file-upload/', from: 'css/jquery.fileupload.css', to: 'css' }, + { context: 'app/bower_components/modernizr/', from: 'modernizr.js' }, + { context: 'app/bower_components/lodash/dist/', from: 'lodash.min.js' }, + { context: 'app/bower_components/jquery/dist/', from: 'jquery.min.js' }, + { context: 'app/bower_components/jquery-ui/', from: 'jquery-ui.min.js' }, + { context: 'app/bower_components/jquery-file-upload/js/', from: 'jquery.fileupload.js' }, + { context: 'app/bower_components/handlebars/', from: 'handlebars.min.js' }, + { context: 'app/bower_components/typeahead.js/dist/', from: 'typeahead.bundle.min.js' }, + { context: 'app/bower_components/iframe-resizer/js/', from: 'iframeResizer.min.js' }, + { context: 'app/bower_components/iframe-resizer/js/', from: 'iframeResizer.contentWindow.min.js' }, + { context: 'app/bower_components/foundation/js/', from: 'foundation.js' }, + { context: 'app/bower_components/foundation/js/foundation/', from: 'foundation.reveal.js' }, + { context: 'app/bower_components/foundation/js/foundation/', from: 'foundation.offcanvas.js' }, + { context: 'app/js/foundation/', from: 'initialize_foundation.js' } +]) diff --git a/web-ui/config/public-assets-webpack.js b/web-ui/config/public-assets-webpack.js new file mode 100644 index 00000000..28dff566 --- /dev/null +++ b/web-ui/config/public-assets-webpack.js @@ -0,0 +1,10 @@ +var CopyWebpackPlugin = require('copy-webpack-plugin'); + +module.exports = new CopyWebpackPlugin([ + { context: 'src/login/', from: '*.html' }, + { context: 'src/login/', from: '*.css' }, + { context: 'src/interstitial/', from: '*' }, + { context: 'app/', from: 'fonts/*' }, + { context: 'app/', from: 'locales/**/*' }, + { context: 'app/', from: 'images/**/*' } +]); diff --git a/web-ui/src/backup_account/backup_account.html b/web-ui/src/backup_account/backup_account.html index fa026e7a..55881444 100644 --- a/web-ui/src/backup_account/backup_account.html +++ b/web-ui/src/backup_account/backup_account.html @@ -1,7 +1,7 @@ - + diff --git a/web-ui/src/backup_account/page.js b/web-ui/src/backup_account/page.js index c39394e2..cc93a560 100644 --- a/web-ui/src/backup_account/page.js +++ b/web-ui/src/backup_account/page.js @@ -34,7 +34,7 @@ export const Page = ({ t }) => (
{t('backup-account.image-description')}
diff --git a/web-ui/src/common/footer/footer.js b/web-ui/src/common/footer/footer.js index 254a19f7..c2138c21 100644 --- a/web-ui/src/common/footer/footer.js +++ b/web-ui/src/common/footer/footer.js @@ -22,7 +22,7 @@ import './footer.scss'; export const Footer = ({ t }) => (