diff --git a/app/partials/public.pug b/app/partials/public.pug index 2cc0265b2d..2d0eb6005a 100644 --- a/app/partials/public.pug +++ b/app/partials/public.pug @@ -1,6 +1,8 @@ .login-pg(ng-class="{'display-block': isUIOverflow}") include ./bc-logo-header - testnet-warning + .banners-container + testnet-warning + block-alert.public-block-alert-overrides(ng-if="showPublicBanner" config="publicBannerConfig") .overflow-scroll.flex-justify.flex-center .flex-center.flex-justify.flex-column .flex.flex-justify diff --git a/assets/css/modules/_signin.scss b/assets/css/modules/_signin.scss index 5bd605a099..57038d45bd 100644 --- a/assets/css/modules/_signin.scss +++ b/assets/css/modules/_signin.scss @@ -13,10 +13,23 @@ div.login-form { height: 100%; position: relative; background-color: $blue; - testnet-warning { + .banners-container { top: 100px; position: relative; } + .public-block-alert-overrides { + .block-alert { + border: none; + padding: 10px 40px; + } + * { + margin: 0px !important; + } + span, p { + font-weight: 300 !important; + margin-bottom: 10px !important; + } + } nav { position: fixed; width: 100%; diff --git a/assets/js/controllers/login.controller.js b/assets/js/controllers/login.controller.js index 72574dd12c..46419e2785 100644 --- a/assets/js/controllers/login.controller.js +++ b/assets/js/controllers/login.controller.js @@ -2,7 +2,7 @@ angular .module('walletApp') .controller('LoginCtrl', LoginCtrl); -function LoginCtrl ($scope, $rootScope, $window, localStorageService, $state, $stateParams, $timeout, $q, Alerts, Wallet, WalletNetwork, Env) { +function LoginCtrl ($scope, $rootScope, $window, localStorageService, $state, $stateParams, $timeout, $q, Alerts, Wallet, WalletNetwork, Env, ComMigration) { $scope.settings = Wallet.settings; $scope.user = Wallet.user; @@ -73,4 +73,9 @@ function LoginCtrl ($scope, $rootScope, $window, localStorageService, $state, $s Env.then((env) => { $scope.showMobileLogin = env.showMobileLogin; }); + + $scope.$on(ComMigration.events.TRANSFERRED_COOKIES, () => $timeout(() => { + let guid = localStorageService.get('guid') + if (guid != null) $scope.uid = guid + })) } diff --git a/assets/js/landingCtrl.js b/assets/js/landingCtrl.js index 70dfabd9a0..0ebd70f2f8 100644 --- a/assets/js/landingCtrl.js +++ b/assets/js/landingCtrl.js @@ -1,6 +1,6 @@ angular.module('walletApp').controller('LandingCtrl', LandingCtrl); -function LandingCtrl ($scope, $http, $state, $sce, languages, Env, walletStats) { +function LandingCtrl ($scope, $http, $state, $sce, languages, Env, walletStats, ComMigration) { Env.then(env => { $scope.network = env.network; $scope.rootURL = env.rootURL; @@ -49,4 +49,8 @@ function LandingCtrl ($scope, $http, $state, $sce, languages, Env, walletStats) $scope.$watch(languages.get, (code) => { $scope.language = languages.mapCodeToName(code); }); + + ComMigration.whenRedirectsEnabled((env) => { + ComMigration.redirectFromDotInfoTo(`${env.domains.comRoot}/wallet`) + }) } diff --git a/assets/js/routes.js b/assets/js/routes.js index e08cd89754..a1e0275c11 100644 --- a/assets/js/routes.js +++ b/assets/js/routes.js @@ -98,23 +98,36 @@ function AppRouter ($stateProvider, $urlRouterProvider) { views: { body: { templateUrl: 'partials/public.pug', - controller: function ($scope, $state, languages, Env) { + controller: function ($scope, $state, $location, languages, Env, ComMigration) { Env.then(env => { $scope.network = env.network; $scope.rootURL = env.rootURL; $scope.versionMyWallet = env.versionMyWallet; $scope.versionFrontend = env.versionFrontend; + + $scope.publicBannerConfig = ComMigration.isOnDotCom(env) + ? env.web.serviceAlert.publicDotCom + : env.web.serviceAlert.publicDotInfo + $scope.showPublicBanner = $scope.publicBannerConfig != null }); + let overflows = ['/reset-2fa']; $scope.state = $state; $scope.path = $state.current.url; $scope.languages = languages.languages; + $scope.$watch(languages.get, (code) => { $scope.language = languages.mapCodeToName(code); }); + $scope.$watch('state.current.url', (newVal) => { $scope.isUIOverflow = overflows.indexOf(newVal) > -1; }); + + ComMigration.whenRedirectsEnabled((env) => { + let url = $location.url() + ComMigration.redirectFromDotInfoTo(`${env.domains.comWalletApp}/#${url}`) + }) } } }, @@ -264,7 +277,7 @@ function AppRouter ($stateProvider, $urlRouterProvider) { accounts ($injector, $q) { let MyWallet = $injector.has('MyWallet') && $injector.get('MyWallet'); let sfox = MyWallet.wallet && MyWallet.wallet.external && MyWallet.wallet.external.sfox; - + return sfox && sfox.hasAccount ? $q.resolve([]) .then(() => sfox.getBuyMethods()).catch(console.log) diff --git a/assets/js/services/wallet.service.js b/assets/js/services/wallet.service.js index cc07e91859..8b68d8f1ab 100644 --- a/assets/js/services/wallet.service.js +++ b/assets/js/services/wallet.service.js @@ -4,10 +4,12 @@ angular .module('walletApp') .factory('Wallet', Wallet); -Wallet.$inject = ['$http', '$window', '$timeout', '$location', '$injector', 'Alerts', 'MyWallet', 'MyBlockchainApi', 'MyBlockchainRng', 'MyBlockchainSettings', 'MyWalletStore', 'MyWalletHelpers', '$rootScope', 'AngularHelper', 'ngAudio', 'localStorageService', '$translate', '$filter', '$state', '$q', 'languages', 'currency', 'theme', 'BlockchainConstants', 'Env', 'BrowserHelper']; +Wallet.$inject = ['$http', '$window', '$timeout', '$location', '$injector', 'Alerts', 'MyWallet', 'MyBlockchainApi', 'MyBlockchainRng', 'MyBlockchainSettings', 'MyWalletStore', 'MyWalletHelpers', '$rootScope', 'AngularHelper', 'ngAudio', 'localStorageService', '$translate', '$filter', '$state', '$q', 'languages', 'currency', 'theme', 'BlockchainConstants', 'Env', 'BrowserHelper', 'ComMigration']; -function Wallet ($http, $window, $timeout, $location, $injector, Alerts, MyWallet, MyBlockchainApi, MyBlockchainRng, MyBlockchainSettings, MyWalletStore, MyWalletHelpers, $rootScope, AngularHelper, ngAudio, localStorageService, $translate, $filter, $state, $q, languages, currency, theme, BlockchainConstants, Env, BrowserHelper) { +function Wallet ($http, $window, $timeout, $location, $injector, Alerts, MyWallet, MyBlockchainApi, MyBlockchainRng, MyBlockchainSettings, MyWalletStore, MyWalletHelpers, $rootScope, AngularHelper, ngAudio, localStorageService, $translate, $filter, $state, $q, languages, currency, theme, BlockchainConstants, Env, BrowserHelper, ComMigration) { BrowserHelper.migrateCookiesToLocalStorage(); + ComMigration.transferCookiesFromDotInfo(); + const wallet = { goal: { auth: false, diff --git a/assets/js/sharedServices/com-migration.service.js b/assets/js/sharedServices/com-migration.service.js new file mode 100644 index 0000000000..48738fbd1f --- /dev/null +++ b/assets/js/sharedServices/com-migration.service.js @@ -0,0 +1,80 @@ +angular + .module('shared') + .factory('ComMigration', ComMigration) + +ComMigration.$inject = ['$rootScope', '$window', 'localStorageService', 'Env'] + +function ComMigration ($rootScope, $window, localStorageService, Env) { + const events = { + TRANSFERRED_COOKIES: 'ComMigration.TRANSFERRED_COOKIES' + } + + return { + events, + isOnDotCom, + isOnDotInfo, + whenRedirectsEnabled, + redirectFromDotInfoTo, + transferCookiesFromDotInfo + } + + function isOnDotCom (env) { + if (env == null) throw new Error('isOnDotCom expects an environment') + return $window.location.origin === env.domains.comWalletApp + } + + function isOnDotInfo (env) { + if (env == null) throw new Error('isOnDotInfo expects an environment') + return $window.location.origin === env.domains.root + } + + function whenRedirectsEnabled (runCallback) { + Env.then((env) => { + if (isOnDotInfo(env) && env.enableDomainMigrationRedirects) { + runCallback(env) + } + }) + } + + function redirectFromDotInfoTo (target) { + Env.then((env) => { + if (isOnDotInfo(env)) { + $window.location = target + } + }) + } + + function transferCookiesFromDotInfo () { + let alreadyTransferredCookiesKey = 'did_already_transfer_cookies_from_dot_info' + let shouldTransfer = localStorageService.get(alreadyTransferredCookiesKey) == null + + let createFrame = (src) => { + let frame = document.createElement('iframe') + frame.src = src + frame.style.display = 'none' + document.body.appendChild(frame) + return frame + } + + Env.then((env) => { + if (isOnDotCom(env) && shouldTransfer) { + let frame = createFrame(`${env.domains.root}/transfer_cookies.html`) + + $window.addEventListener('message', (event) => { + if (event.data.type === 'cookie') { + let cookie = event.data.payload + localStorageService.set(cookie.id, cookie.data) + } + + if (event.data.type === 'cookies-sent') { + frame.remove() + localStorageService.set(alreadyTransferredCookiesKey, 'yes') + $rootScope.$broadcast(events.TRANSFERRED_COOKIES) + } + }) + } + }).catch((error) => { + console.error('Error transferring cookies', error); + }) + } +} diff --git a/assets/js/sharedServices/env.service.js b/assets/js/sharedServices/env.service.js index f31c1db312..484472ad36 100644 --- a/assets/js/sharedServices/env.service.js +++ b/assets/js/sharedServices/env.service.js @@ -31,6 +31,8 @@ function Env ($rootScope, $location, $q, $http) { env.showBuySellTab = res.showBuySellTab; env.service_charge = res.service_charge; + env.domains = res.domains + env.rootURL = res.domains.root + '/'; env.showMobileLogin = !!res.showMobileLogin; @@ -63,6 +65,8 @@ function Env ($rootScope, $location, $q, $http) { env.webHardFork = res.webHardFork || {}; + env.enableDomainMigrationRedirects = res.enableDomainMigrationRedirects || false + defer.resolve(env); } ); diff --git a/rootApp/Resources/wallet-options.json b/rootApp/Resources/wallet-options.json index 74f32d485d..01a5a218eb 100644 --- a/rootApp/Resources/wallet-options.json +++ b/rootApp/Resources/wallet-options.json @@ -1,4 +1,5 @@ { + "enableDomainMigrationRedirects": false, "showBuySellTab": ["GB", "NL", "DE", "US"], "service_charge": { "US": { @@ -69,6 +70,8 @@ }, "domains": { "root": "REPLACED_BY_DEV_SERVER", + "comRoot": "REPLACED_BY_DEV_SERVER", + "comWalletApp": "REPLACED_BY_DEV_SERVER", "webSocket": "REPLACED_BY_DEV_SERVER", "api": "REPLACED_BY_DEV_SERVER", "walletHelperUrl": "REPLACED_BY_DEV_SERVER" @@ -94,6 +97,25 @@ }, "web": { "serviceAlert": { + "__publicDotInfo": { + "type": "info", + "header": { + "en": "We’re packing our bags and preparing to move…domains!" + }, + "sections": [ + { + "body": { + "en": "To make way for our new and exciting products coming this year, we’re saying hello to our new home. Your Blockchain Wallet will soon be changing URLs as it's combined with our company site, blockchain.com." + } + } + ], + "action": { + "title": { + "en": "Read more about what to expect here." + }, + "link": "https://www.example.com/" + } + }, "__global": { "type": "warning", "hideType": "collapse", diff --git a/server.js b/server.js index 7e301c84ff..5f40cb59a1 100644 --- a/server.js +++ b/server.js @@ -17,6 +17,7 @@ var apiDomain = process.env.API_DOMAIN; var production = Boolean(rootURL === 'https://blockchain.info'); var iSignThisDomain = production ? 'https://verify.isignthis.com/' : 'https://stage-verify.isignthis.com/'; var walletHelperFrameDomain = process.env.WALLET_HELPER_URL || `http://localhost:${ walletHelperPort }`; +var cookieTransferDomain = process.env.COOKIE_TRANSFER_DOMAIN var sfoxProduction = parseInt(process.env.SFOX_USE_PRODUCTION, 10) === 1; var unocoinProduction = parseInt(process.env.UNOCOIN_USE_PRODUCTION, 10) === 1; @@ -51,8 +52,8 @@ app.use(function (req, res, next) { // Safari throws the same error, but without suggesting an hash to whitelist. // Firefox appears to just allow unsafe-inline CSS "style-src 'self' 'uD+9kGdg1SXQagzGsu2+gAKYXqLRT/E07bh4OhgXN8Y=' '4IfJmohiqxpxzt6KnJiLmxBD72c3jkRoQ+8K5HT5K8o='", - `child-src ${ walletHelperFrameDomain } ${ iSignThisDomain} `, - `frame-src ${ walletHelperFrameDomain } ${ iSignThisDomain} `, + `child-src ${walletHelperFrameDomain} ${iSignThisDomain} ${cookieTransferDomain} `, + `frame-src ${walletHelperFrameDomain} ${iSignThisDomain} ${cookieTransferDomain} `, "script-src 'self'", 'connect-src ' + [ "'self'", @@ -147,6 +148,8 @@ rootApp.use(function (req, res, next) { var parsedJSON = require('./rootApp/Resources/wallet-options.json'); parsedJSON.domains = { root: process.env.ROOT_URL, + comRoot: process.env.BLOCKCHAIN_COM_ROOT_URL, + comWalletApp: process.env.BLOCKCHAIN_COM_WALLET_APP_URL, webSocket: process.env.WEB_SOCKET_URL, api: process.env.API_DOMAIN, walletHelperUrl: walletHelperFrameDomain