Hesla neopakujte, neměňte si je a hlavně si je nepamatujte

14. 10. 2019
Doba čtení: 6 minut

Sdílet

Autor: Dalibor Z. Chvátal
Pravidla pro práci s hesly by měla kopírovat současnou bezpečnostní praxi. Doporučení a standardy existují, ale staré pořádky se drží velmi dlouho. Jak si vytvářet správné heslo a jak s ním nakládat?

V reakci na článek Neměníte hesla dost často a nechráníte si je? Škodu vám nikdo neuhradí, který mylně popisuje, jak si vytvářet hesla, autor napsal tento odborný text určený pro širokou veřejnost. Další text o Zabezpečení na úkor použitelnosti, které jde na úkor bezpečnosti popsal pro náš sesterský portál Lupa.cz bezpečnostní expert Michal Špaček.

Heslo je stále naprosto zásadním identifikačním prvkem. Jeho znalost vás odlišuje od náhodného kolemjdoucího. Jen podle hesla počítač či služba pozná, že jste to opravdu vy. Svět se ale rychle mění a s tím přichází nové hrozby, na které je potřeba reagovat.

Zastaralá pravidla pro práci s hesly ohrožují bezpečnost současných uživatelů, dávají špatné příklady a zjednodušují práci útočníkům. Bohužel hrozby jsou velmi reálné, úspěšné útoky běžné a finanční ztráty bolestivé. Nechcete, aby vám někdo vybral účet nebo vám ukradl celý digitální život.

Je na čase revidovat stará pravidla a reagovat na to, co se opravdu ve světě děje. Už dávno neplatí, že byste měli heslo změnit každých třicet dnů a nesmíte si jej nikam zapsat. Pokud to po vás firma stále chce, ukažte šéfovi tenhle článek, který mu otevře oči a ukáže, že jsme o dvacet let dál.

Nová služba, nové heslo

Dříve se v pravidlech a doporučeních kladl velký důraz na sílu hesla: délka, speciální znaky, vynechat jméno kočky a podobně. Tohle rozhodně stále platí. Heslo Katka11 je velmi špatné, zvlášť, když si všichni na světě na vaší oblíbené sociální síti přečtou jméno vaší dcery a datum narození.

V posledních letech se ale ukazuje, že stejně důležitá je i unikátnost hesla. Hesla totiž unikají. Dnes a denně se daří napadat jednotlivé služby a vylákat z nich seznam hesel všech uživatelů. Seznamy se pak válejí po internetu a obvykle jsou doplněny o e-mailové adresy. Je tedy úplně jedno, že jste si vymysleli geniální náhodné heslo YJe4hfa@Tx6,#zwR, pokud se dá pomocí Google najít vedle vaší e-mailové adresy.

Bezpečnostní expert Troy Hunt tyto databáze sbírá a nahrává do své služby Have I Been Pwned (článek v češtině), kde si můžete podle své e-mailové adresy nebo hesla vyhledat, zda jste nebyli v nějakém úniku. Schválně si tam zkuste zadat svou e-mailovou adresu. Možná budete překvapeni, z kolika služeb už vaše heslo uniklo.

Mělo by tedy platit, že na každou službu používáte heslo právě jednou. Pokud pak dojde k úniku hesel, nebude vás to bolet. Prostě si jen na dané službě heslo změníte a tím je pro vás problém vyřešený. Bude vás to bolet rozhodně méně, než kdybyste tohle jedno heslo používali v bance, hlavním e-mailu, účetním systému a bůhví kde ještě.

Pravidlo první: hesla nikdy neopakujeme.

Nucená změna hesla je špatně

„Vaše heslo vyprší za tři dny, musíte si ho změnit.“ Bohužel velmi špatná praxe, pevně zakořeněná ve spoustě firem. Nedávno mi jedna paní vyprávěla, že je v nové práci rok a půl a už měla 16 hesel. Šestnáct. Jak si myslíte, že jsou ta hesla silná? Jsou opravdu unikátní? Je taková změna k něčemu? Samozřejmě, že není.

Pravidelná změna hesla nezvyšuje bezpečnost, naopak ji dramaticky snižuje. Vede totiž ke zjednodušování hesel, opakování a triviální variabilitě. Vsadím se, že vaše další heslo bude Katka12 a to další pak Katka13. Tohle opravdu není bezpečné, protože to nahrává útočníkům.

Pokud se dozvím, že firma nutí pravidelně měnit hesla své zaměstnance, mám napůl vyhráno. Zvlášť, pokud k tomu dohledám v únicích nějaké předchozí varianty hesel některých z nich. Pokud totiž uživatelům zkomplikujete život, začnou hledat zkratky, jak obejít pravidla. Pokud jim nasypete na hlavu hromadu pravidel týkajících se hesel, můžete si být jisti, že je splní cestou nejmenšího odporu.

Jsou jen dva případy, kdy je legitimní měnit si heslo: pokud máte podezření na jeho únik nebo pokud chcete heslo silnější. Jiné důvody jsou neobhajitelné a nemají s bezpečností nic společného. Rozhodně nevymyslíte silnější heslo dvanáctkrát do roka.

Pravidlo druhé: neměňte zbytečně hesla.

Nepamatujte si hesla

Možná teď přemýšlíte, jak tohle všechno máte udržet v hlavě, když máte do každé kolonky vyplňovat jiné heslo a ještě velmi složité. Odpověď je jednoduchá: nijak. Bezpečnostní odborník Michal Špaček říká, že hlava není na hesla. Má pravdu. Pokud chcete dodržovat základní pravidla bezpečnosti, nemůžete si hesla pamatovat.

Snaha nacpat si všechna hesla do hlavy vede opět nutně ke zjednodušování. Buď budete používat dvě hesla na všech webech, nebo budete mít jeden základ, který budete opět triviálně variovat. Katka11seznam. Že vás to napadlo?

Jediným bezpečným východiskem je hesla si zapsat. Přestože do vás dvacet let cpou, že si heslo nesmíte nikam zapsat, je to nejlepší způsob, jak zůstat v bezpečí. Pokud máte hesla zapsaná, můžete si snadno vytvářet nová, lehce měnit v případě nutnosti ta stará a pořád budete mít hesla silná a hlavně unikátní.

Nejlepší je použít správce hesel. To jsou nástroje, které umožňují mít v zašifrované databázi uložené libovolné citlivé údaje. Pamatujete si pak jedno jediné silné heslo, kterým dokážete soubor odemknout a podívat se do něj na ostatní hesla. Nástrojů existuje celá řada, ale správce hesel je dnes integrovaný ve webovém prohlížeči, takže si můžete prostě hesla ukládat do něj. Je to nejjednodušší a navíc vám to jednoduše umožňuje generovat hesla náhodně, což je pro bezpečnost vůbec nejlepší.

Pokud něco takového nejste ochotni používat, poslouží vám obyčejný notýsek a tužka. Vážně. Pořád platí, že takhle uložená hesla budou bezpečnější, silnější a unikátnější než ta dvě, která si pamatujete dnes. Když překonáte naučený odpor, zlepšíte tím dramaticky svou bezpečnost.

„Ale to je strašně nebezpečné!“ Není. Chráníte se před online hrozbami, hádáním hesel a používáním hesel z úniků. Svému okolí pravděpodobně věříte, necháváte na stole v kanceláři peněženku, mobil, klíče od domu a doklady od auta. Nevěříte neznámým lidem v parku a na internetu. Nenechávejte tedy po světě povalovat klíče, stejně jako nerozdávejte po internetu jedno unikátní heslo na počkání všem službám.

Odpůrci správců hesel argumentují tím, že při úspěšném napadení počítače má útočník možnost hesla snadno získat. Ve skutečnosti nemá ukládání hesel v počítači žádný dopad na jejich bezpečnost. Útočník s přístupem do vašeho systému může úplně v klidu do počítače nainstalovat skrytý škodlivý program, který bude odposlouchávat vaši klávesnici a heslo mu pošle, až ho příště naťukáte. Jakmile je útočník uvnitř, má neomezené možnosti a hesla ve vaší hlavě pro něj nejsou vůbec žádnou překážkou. Dobré zabezpečení vašeho počítače je v každém případě naprosto zásadní.

Pravidlo třetí: hesla si někam zapište.

Použijte druhý faktor

Když už vám heslo k nějaké službě unikne, může se místo vás přihlásit kdokoliv. Existuje pak už jen doplňková ochrana v podobě dvoufaktorové autorizace. Ta umožňuje k heslu (něco znáte) přidat ještě další bezpečnostní prvek, kterým se musíte prokázat (něco vlastníte). Třeba kromě zadání hesla potvrdíte autorizaci na mobilu.

bitcoin_smenarna

Pravděpodobně to dávno znáte z banky, která vám kromě přihlášení hesla ještě nějakým způsobem pošle potvrzovací zprávu. Nejhorší a nedoporučovanou metodou je opisovat kód z SMS, což je jednak nepohodlné, ale také nejméně bezpečné. Už bylo mnohokrát prokázáno, že mobilní komunikaci je možné přesměrovat a překvapivě snadno u některých operátorů vylákáte náhradní SIM kartu k cizí službě. Pokud vám někdo takto unese číslo, máte o problém navíc. Ale i SMS je lepší než nic.

Mnoho dnešních bank a služeb umí potvrzení provést přes bezpečnostní aplikaci, kterou máte nainstalovanou na chytrém telefonu. Tam vám vyskočí hláška, která říká, že se někdo snaží přihlásit na váš účet. Pokud jste to vy, stačí potvrdit autorizaci přiložením prstu na senzor a proběhne přihlášení. Pokud by útočník přečetl heslo ve vašem notýsku, nemá váš mobil a váš prst. Vy tak snadno odhalíte snahu o podvod, heslo si změníte, snadno přepíšete a jste zase v bezpečí.

Pravidlo čtvrté: zapněte si dvoufaktorové přihlašování.

Autor článku

Petr Krčmář pracuje jako šéfredaktor serveru Root.cz. Studoval počítače a média, takže je rozpolcen mezi dva obory. Snaží se dělat obojí, jak nejlépe umí.

'; document.getElementById('preroll-iframe').onload = function () { setupIframe(); } prerollContainer = document.getElementsByClassName('preroll-container-iframe')[0]; } function setupIframe() { prerollDocument = document.getElementById('preroll-iframe').contentWindow.document; let el = prerollDocument.createElement('style'); prerollDocument.head.appendChild(el); el.innerText = "#adContainer>div:nth-of-type(1),#adContainer>div:nth-of-type(1) > iframe { width: 99% !important;height: 99% !important;max-width: 100%;}#videoContent,body{ width:100vw;height:100vh}body{ font-family:'Helvetica Neue',Arial,sans-serif}#videoContent{ overflow:hidden;background:#000}#adMuteBtn{ width:35px;height:35px;border:0;background:0 0;display:none;position:absolute;fill:rgba(230,230,230,1);bottom:20px;right:25px}"; videoContent = prerollDocument.getElementById('contentElement'); videoContent.style.display = 'none'; videoContent.volume = 1; videoContent.muted = false; const playPromise = videoContent.play(); if (playPromise !== undefined) { playPromise.then(function () { console.log('PREROLL sound allowed'); // setUpIMA(true); videoContent.volume = 1; videoContent.muted = false; setUpIMA(); }).catch(function () { console.log('PREROLL sound forbidden'); videoContent.volume = 0; videoContent.muted = true; setUpIMA(); }); } } function setupDimensions() { prerollWidth = Math.min(iinfoPrerollPosition.offsetWidth, 480); prerollHeight = Math.min(iinfoPrerollPosition.offsetHeight, 320); } function setUpIMA() { google.ima.settings.setDisableCustomPlaybackForIOS10Plus(true); google.ima.settings.setLocale('cs'); google.ima.settings.setNumRedirects(10); // Create the ad display container. createAdDisplayContainer(); // Create ads loader. adsLoader = new google.ima.AdsLoader(adDisplayContainer); // Listen and respond to ads loaded and error events. adsLoader.addEventListener( google.ima.AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED, onAdsManagerLoaded, false); adsLoader.addEventListener( google.ima.AdErrorEvent.Type.AD_ERROR, onAdError, false); // An event listener to tell the SDK that our content video // is completed so the SDK can play any post-roll ads. const contentEndedListener = function () { adsLoader.contentComplete(); }; videoContent.onended = contentEndedListener; // Request video ads. const adsRequest = new google.ima.AdsRequest(); adsRequest.adTagUrl = iinfoVastUrls[iinfoVastUrlIndex]; console.log('Preroll advert: ' + iinfoVastUrls[iinfoVastUrlIndex]); videoContent.muted = false; videoContent.volume = 1; // Specify the linear and nonlinear slot sizes. This helps the SDK to // select the correct creative if multiple are returned. // adsRequest.linearAdSlotWidth = prerollWidth; // adsRequest.linearAdSlotHeight = prerollHeight; adsRequest.nonLinearAdSlotWidth = 0; adsRequest.nonLinearAdSlotHeight = 0; adsLoader.requestAds(adsRequest); } function createAdDisplayContainer() { // We assume the adContainer is the DOM id of the element that will house // the ads. prerollDocument.getElementById('videoContent').style.display = 'none'; adDisplayContainer = new google.ima.AdDisplayContainer( prerollDocument.getElementById('adContainer'), videoContent); } function unmutePrerollAdvert() { adVolume = !adVolume; if (adVolume) { adsManager.setVolume(0.3); prerollDocument.getElementById('adMuteBtn').innerHTML = ''; } else { adsManager.setVolume(0); prerollDocument.getElementById('adMuteBtn').innerHTML = ''; } } function onAdsManagerLoaded(adsManagerLoadedEvent) { // Get the ads manager. const adsRenderingSettings = new google.ima.AdsRenderingSettings(); adsRenderingSettings.restoreCustomPlaybackStateOnAdBreakComplete = true; adsRenderingSettings.loadVideoTimeout = 12000; // videoContent should be set to the content video element. adsManager = adsManagerLoadedEvent.getAdsManager(videoContent, adsRenderingSettings); // Add listeners to the required events. adsManager.addEventListener(google.ima.AdErrorEvent.Type.AD_ERROR, onAdError); adsManager.addEventListener( google.ima.AdEvent.Type.CONTENT_PAUSE_REQUESTED, onContentPauseRequested); adsManager.addEventListener( google.ima.AdEvent.Type.CONTENT_RESUME_REQUESTED, onContentResumeRequested); adsManager.addEventListener( google.ima.AdEvent.Type.ALL_ADS_COMPLETED, onAdEvent); // Listen to any additional events, if necessary. adsManager.addEventListener(google.ima.AdEvent.Type.LOADED, onAdEvent); adsManager.addEventListener(google.ima.AdEvent.Type.STARTED, onAdEvent); adsManager.addEventListener(google.ima.AdEvent.Type.COMPLETE, onAdEvent); playAds(); } function playAds() { // Initialize the container. Must be done through a user action on mobile // devices. videoContent.load(); adDisplayContainer.initialize(); // setupDimensions(); try { // Initialize the ads manager. Ad rules playlist will start at this time. adsManager.init(1920, 1080, google.ima.ViewMode.NORMAL); // Call play to start showing the ad. Single video and overlay ads will // start at this time; the call will be ignored for ad rules. adsManager.start(); // window.addEventListener('resize', function (event) { // if (adsManager) { // setupDimensions(); // adsManager.resize(prerollWidth, prerollHeight, google.ima.ViewMode.NORMAL); // } // }); } catch (adError) { // An error may be thrown if there was a problem with the VAST response. // videoContent.play(); } } function onAdEvent(adEvent) { const ad = adEvent.getAd(); console.log('Preroll event: ' + adEvent.type); switch (adEvent.type) { case google.ima.AdEvent.Type.LOADED: if (!ad.isLinear()) { videoContent.play(); } prerollDocument.getElementById('adContainer').style.width = '100%'; prerollDocument.getElementById('adContainer').style.maxWidth = '640px'; prerollDocument.getElementById('adContainer').style.height = '360px'; break; case google.ima.AdEvent.Type.STARTED: window.addEventListener('scroll', onActiveView); if (ad.isLinear()) { intervalTimer = setInterval( function () { // Example: const remainingTime = adsManager.getRemainingTime(); // adsManager.pause(); }, 300); // every 300ms } prerollDocument.getElementById('adMuteBtn').style.display = 'block'; break; case google.ima.AdEvent.Type.ALL_ADS_COMPLETED: if (ad.isLinear()) { clearInterval(intervalTimer); } if (prerollLastError === 303) { playYtVideo(); } break; case google.ima.AdEvent.Type.COMPLETE: if (ad.isLinear()) { clearInterval(intervalTimer); } playYtVideo(); break; } } function onAdError(adErrorEvent) { console.log(adErrorEvent.getError()); prerollLastError = adErrorEvent.getError().getErrorCode(); if (!loadNext()) { playYtVideo(); } } function loadNext() { iinfoVastUrlIndex++; if (iinfoVastUrlIndex < iinfoVastUrls.length) { iinfoPrerollPosition.remove(); playPrerollAd(); } else { return false; } adVolume = 1; return true; } function onContentPauseRequested() { videoContent.pause(); } function onContentResumeRequested() { videoContent.play(); } function onActiveView() { if (prerollContainer) { const containerOffset = prerollContainer.getBoundingClientRect(); const windowHeight = window.innerHeight; if (containerOffset.top < windowHeight/1 && containerOffset.bottom > 0.0) { if (prerollPaused) { adsManager.resume(); prerollPaused = false; } return true; } else { if (!prerollPaused) { adsManager.pause(); prerollPaused = true; } } } return false; } function playYtVideo() { iinfoPrerollPosition.remove(); youtubeIframe.style.display = 'block'; youtubeIframe.src += '&autoplay=1&mute=1'; } }
Upozorníme vás na články, které by vám neměly uniknout (maximálně 2x týdně).
'; document.getElementById('outstream-iframe').onload = function () { setupIframe(); } replayScreen = document.getElementById('iinfoOutstreamReplay'); iinfoOutstreamPosition = document.getElementById('iinfoOutstreamPosition'); outstreamContainer = document.getElementsByClassName('outstream-container')[0]; setupReplayScreen(); } function setupIframe() { outstreamDocument = document.getElementById('outstream-iframe').contentWindow.document; let el = outstreamDocument.createElement('style'); outstreamDocument.head.appendChild(el); el.innerText = "#adContainer>div:nth-of-type(1),#adContainer>div:nth-of-type(1) > iframe { width: 99% !important;height: 99% !important;max-width: 100%;}#videoContent,body{ width:100vw;height:100vh}body{ font-family:'Helvetica Neue',Arial,sans-serif}#videoContent{ overflow:hidden;background:#000}#adMuteBtn{ width:35px;height:35px;border:0;background:0 0;display:none;position:absolute;fill:rgba(230,230,230,1);bottom:-5px;right:25px}"; videoContent = outstreamDocument.getElementById('contentElement'); videoContent.style.display = 'none'; videoContent.volume = 1; videoContent.muted = false; if ( location.href.indexOf('rejstriky.finance.cz') !== -1 || location.href.indexOf('finance-rejstrik') !== -1 || location.href.indexOf('firmy.euro.cz') !== -1 || location.href.indexOf('euro-rejstrik') !== -1 || location.href.indexOf('/rejstrik/') !== -1 || location.href.indexOf('/rejstrik-firem/') !== -1) { outstreamDirectPlayed = true; soundAllowed = true; iinfoVastUrlIndex = 0; } if (!outstreamDirectPlayed) { console.log('OUTSTREAM direct'); setUpIMA(true); } else { if (soundAllowed) { const playPromise = videoContent.play(); if (playPromise !== undefined) { playPromise.then(function () { console.log('OUTSTREAM sound allowed'); setUpIMA(false); }).catch(function () { console.log('OUTSTREAM sound forbidden'); renderBanner(); }); } } else { renderBanner(); } } } function getWrapper() { let articleWrapper = document.querySelector('.rs-outstream-placeholder'); // Outstream Placeholder from RedSys manipulation if (articleWrapper && articleWrapper.style.display !== 'block') { articleWrapper.innerHTML = ""; articleWrapper.style.display = 'block'; } // Don't render OutStream on homepages if (articleWrapper === null) { if (document.querySelector('body.p-index')) { return null; } } if (articleWrapper === null) { articleWrapper = document.getElementById('iinfo-outstream'); } if (articleWrapper === null) { articleWrapper = document.querySelector('.layout-main__content .detail__article p:nth-of-type(6)'); } if (articleWrapper === null) { // Euro, Autobible, Zdravi articleWrapper = document.querySelector('.o-article .o-article__text p:nth-of-type(6)'); } if (articleWrapper === null) { articleWrapper = document.getElementById('sidebar'); } if (!articleWrapper) { console.error("Outstream wrapper of article was not found."); } return articleWrapper; } function setupDimensions() { outstreamWidth = Math.min(iinfoOutstreamPosition.offsetWidth, 480); outstreamHeight = Math.min(iinfoOutstreamPosition.offsetHeight, 320); } /** * Sets up IMA ad display container, ads loader, and makes an ad request. */ function setUpIMA(direct) { google.ima.settings.setDisableCustomPlaybackForIOS10Plus(true); google.ima.settings.setLocale('cs'); google.ima.settings.setNumRedirects(10); // Create the ad display container. createAdDisplayContainer(); // Create ads loader. adsLoader = new google.ima.AdsLoader(adDisplayContainer); // Listen and respond to ads loaded and error events. adsLoader.addEventListener( google.ima.AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED, onAdsManagerLoaded, false); adsLoader.addEventListener( google.ima.AdErrorEvent.Type.AD_ERROR, onAdError, false); // An event listener to tell the SDK that our content video // is completed so the SDK can play any post-roll ads. const contentEndedListener = function () { adsLoader.contentComplete(); }; videoContent.onended = contentEndedListener; // Request video ads. const adsRequest = new google.ima.AdsRequest(); if (direct) { adsRequest.adTagUrl = directVast; console.log('Outstream DIRECT CAMPAING advert: ' + directVast); videoContent.muted = true; videoContent.volume = 0; outstreamDirectPlayed = true; } else { adsRequest.adTagUrl = iinfoVastUrls[iinfoVastUrlIndex]; console.log('Outstream advert: ' + iinfoVastUrls[iinfoVastUrlIndex]); videoContent.muted = false; videoContent.volume = 1; } // Specify the linear and nonlinear slot sizes. This helps the SDK to // select the correct creative if multiple are returned. // adsRequest.linearAdSlotWidth = outstreamWidth; // adsRequest.linearAdSlotHeight = outstreamHeight; adsRequest.nonLinearAdSlotWidth = 0; adsRequest.nonLinearAdSlotHeight = 0; adsLoader.requestAds(adsRequest); } function setupReplayScreen() { replayScreen.addEventListener('click', function () { iinfoOutstreamPosition.remove(); iinfoVastUrlIndex = 0; outstreamInit(); }); } /** * Sets the 'adContainer' div as the IMA ad display container. */ function createAdDisplayContainer() { // We assume the adContainer is the DOM id of the element that will house // the ads. outstreamDocument.getElementById('videoContent').style.display = 'none'; adDisplayContainer = new google.ima.AdDisplayContainer( outstreamDocument.getElementById('adContainer'), videoContent); } function unmuteAdvert() { adVolume = !adVolume; if (adVolume) { adsManager.setVolume(0.3); outstreamDocument.getElementById('adMuteBtn').innerHTML = ''; } else { adsManager.setVolume(0); outstreamDocument.getElementById('adMuteBtn').innerHTML = ''; } } /** * Loads the video content and initializes IMA ad playback. */ function playAds() { // Initialize the container. Must be done through a user action on mobile // devices. videoContent.load(); adDisplayContainer.initialize(); // setupDimensions(); try { // Initialize the ads manager. Ad rules playlist will start at this time. adsManager.init(1920, 1080, google.ima.ViewMode.NORMAL); // Call play to start showing the ad. Single video and overlay ads will // start at this time; the call will be ignored for ad rules. adsManager.start(); // window.addEventListener('resize', function (event) { // if (adsManager) { // setupDimensions(); // adsManager.resize(outstreamWidth, outstreamHeight, google.ima.ViewMode.NORMAL); // } // }); } catch (adError) { // An error may be thrown if there was a problem with the VAST response. // videoContent.play(); } } /** * Handles the ad manager loading and sets ad event listeners. * @param { !google.ima.AdsManagerLoadedEvent } adsManagerLoadedEvent */ function onAdsManagerLoaded(adsManagerLoadedEvent) { // Get the ads manager. const adsRenderingSettings = new google.ima.AdsRenderingSettings(); adsRenderingSettings.restoreCustomPlaybackStateOnAdBreakComplete = true; adsRenderingSettings.loadVideoTimeout = 12000; // videoContent should be set to the content video element. adsManager = adsManagerLoadedEvent.getAdsManager(videoContent, adsRenderingSettings); // Add listeners to the required events. adsManager.addEventListener(google.ima.AdErrorEvent.Type.AD_ERROR, onAdError); adsManager.addEventListener( google.ima.AdEvent.Type.CONTENT_PAUSE_REQUESTED, onContentPauseRequested); adsManager.addEventListener( google.ima.AdEvent.Type.CONTENT_RESUME_REQUESTED, onContentResumeRequested); adsManager.addEventListener( google.ima.AdEvent.Type.ALL_ADS_COMPLETED, onAdEvent); // Listen to any additional events, if necessary. adsManager.addEventListener(google.ima.AdEvent.Type.LOADED, onAdEvent); adsManager.addEventListener(google.ima.AdEvent.Type.STARTED, onAdEvent); adsManager.addEventListener(google.ima.AdEvent.Type.COMPLETE, onAdEvent); playAds(); } /** * Handles actions taken in response to ad events. * @param { !google.ima.AdEvent } adEvent */ function onAdEvent(adEvent) { // Retrieve the ad from the event. Some events (for example, // ALL_ADS_COMPLETED) don't have ad object associated. const ad = adEvent.getAd(); console.log('Outstream event: ' + adEvent.type); switch (adEvent.type) { case google.ima.AdEvent.Type.LOADED: // This is the first event sent for an ad - it is possible to // determine whether the ad is a video ad or an overlay. if (!ad.isLinear()) { // Position AdDisplayContainer correctly for overlay. // Use ad.width and ad.height. videoContent.play(); } outstreamDocument.getElementById('adContainer').style.width = '100%'; outstreamDocument.getElementById('adContainer').style.maxWidth = '640px'; outstreamDocument.getElementById('adContainer').style.height = '360px'; break; case google.ima.AdEvent.Type.STARTED: window.addEventListener('scroll', onActiveView); // This event indicates the ad has started - the video player // can adjust the UI, for example display a pause button and // remaining time. if (ad.isLinear()) { // For a linear ad, a timer can be started to poll for // the remaining time. intervalTimer = setInterval( function () { // Example: const remainingTime = adsManager.getRemainingTime(); // adsManager.pause(); }, 300); // every 300ms } outstreamDocument.getElementById('adMuteBtn').style.display = 'block'; break; case google.ima.AdEvent.Type.ALL_ADS_COMPLETED: if (ad.isLinear()) { clearInterval(intervalTimer); } if (outstreamLastError === 303) { if (isBanner) { renderBanner(); } else { replayScreen.style.display = 'flex'; } } break; case google.ima.AdEvent.Type.COMPLETE: // This event indicates the ad has finished - the video player // can perform appropriate UI actions, such as removing the timer for // remaining time detection. if (ad.isLinear()) { clearInterval(intervalTimer); } if (isBanner) { renderBanner(); } else { replayScreen.style.display = 'flex'; } break; } } /** * Handles ad errors. * @param { !google.ima.AdErrorEvent } adErrorEvent */ function onAdError(adErrorEvent) { // Handle the error logging. console.log(adErrorEvent.getError()); outstreamLastError = adErrorEvent.getError().getErrorCode(); if (!loadNext()) { renderBanner(); } } function renderBanner() { if (isBanner) { console.log('Outstream: Render Banner'); iinfoOutstreamPosition.innerHTML = ""; iinfoOutstreamPosition.style.height = "330px"; iinfoOutstreamPosition.appendChild(bannerDiv); } else { console.log('Outstream: Banner is not set'); } } function loadNext() { iinfoVastUrlIndex++; if (iinfoVastUrlIndex < iinfoVastUrls.length) { iinfoOutstreamPosition.remove(); outstreamInit(); } else { return false; } adVolume = 1; return true; } /** * Pauses video content and sets up ad UI. */ function onContentPauseRequested() { videoContent.pause(); // This function is where you should setup UI for showing ads (for example, // display ad timer countdown, disable seeking and more.) // setupUIForAds(); } /** * Resumes video content and removes ad UI. */ function onContentResumeRequested() { videoContent.play(); // This function is where you should ensure that your UI is ready // to play content. It is the responsibility of the Publisher to // implement this function when necessary. // setupUIForContent(); } function onActiveView() { if (outstreamContainer) { const containerOffset = outstreamContainer.getBoundingClientRect(); const windowHeight = window.innerHeight; if (containerOffset.top < windowHeight/1 && containerOffset.bottom > 0.0) { if (outstreamPaused) { adsManager.resume(); outstreamPaused = false; } return true; } else { if (!outstreamPaused) { adsManager.pause(); outstreamPaused = true; } } } return false; } let outstreamInitInterval; if (typeof cpexPackage !== "undefined") { outstreamInitInterval = setInterval(tryToInitializeOutstream, 100); } else { const wrapper = getWrapper(); if (wrapper) { let outstreamInitialized = false; window.addEventListener('scroll', () => { if (!outstreamInitialized) { const containerOffset = wrapper.getBoundingClientRect(); const windowHeight = window.innerHeight; if (containerOffset.top < windowHeight / 1 && containerOffset.bottom > 0.0) { outstreamInit(); outstreamInitialized = true; } } }); } } function tryToInitializeOutstream() { const wrapper = getWrapper(); if (wrapper) { const containerOffset = wrapper.getBoundingClientRect(); const windowHeight = window.innerHeight; if (containerOffset.top < windowHeight / 1 && containerOffset.bottom > 0.0) { if (cpexPackage.adserver.displayed) { clearInterval(outstreamInitInterval); outstreamInit(); } } } else { clearInterval(outstreamInitInterval); } } }
OSZAR »