1
0
mirror of https://github.com/PrivSec-dev/privsec.dev synced 2024-11-17 20:11:33 -05:00
privsec.dev/public/knowledge/multi-factor-authentication/index.html
Tommy 0543ef9e4a
Hugo Build
Signed-off-by: Tommy <contact@tommytran.io>
2022-07-16 19:53:12 -04:00

8 lines
28 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!doctype html><html lang=en dir=auto><head><meta charset=utf-8><meta http-equiv=x-ua-compatible content="IE=edge"><meta name=viewport content="width=device-width,initial-scale=1,shrink-to-fit=no"><meta name=robots content="index, follow"><title>Multi-factor Authentication | PrivSec.dev</title><meta name=keywords content="knowledge base,security"><meta name=description content="Multi-factor authentication is a security mechanism that requires additional verification beyond your username (or email) and password. This usually comes in the form of a one time passcode, a push notification, or plugging in and tapping a hardware security key.
Common protocols Email and SMS MFA Email and SMS MFA are examples of the weaker MFA protocols. Email MFA is not great as whoever controls your email account can typically both reset your password and recieve your MFA verification."><meta name=author content="Tommy"><link rel=canonical href=https://privsec.dev/knowledge/multi-factor-authentication/><link crossorigin=anonymous href=/assets/css/stylesheet.8b523f1730c922e314350296d83fd666efa16519ca136320a93df674d00b6325.css integrity="sha256-i1I/FzDJIuMUNQKW2D/WZu+hZRnKE2MgqT32dNALYyU=" rel="preload stylesheet" as=style><script defer crossorigin=anonymous src=/assets/js/highlight.f413e19d0714851f6474e7ee9632408e58ac146fbdbe62747134bea2fa3415e0.js integrity="sha256-9BPhnQcUhR9kdOfuljJAjlisFG+9vmJ0cTS+ovo0FeA=" onload=hljs.initHighlightingOnLoad()></script>
<link rel=icon href=https://privsec.dev/%3Clink%20/%20abs%20url%3E><link rel=icon type=image/png sizes=16x16 href=https://privsec.dev/%3Clink%20/%20abs%20url%3E><link rel=icon type=image/png sizes=32x32 href=https://privsec.dev/%3Clink%20/%20abs%20url%3E><link rel=apple-touch-icon href=https://privsec.dev/%3Clink%20/%20abs%20url%3E><link rel=mask-icon href=https://privsec.dev/%3Clink%20/%20abs%20url%3E><meta name=theme-color content="#2e2e33"><meta name=msapplication-TileColor content="#2e2e33"><noscript><style>#theme-toggle,.top-link{display:none}</style></noscript><meta property="og:title" content="Multi-factor Authentication"><meta property="og:description" content="Multi-factor authentication is a security mechanism that requires additional verification beyond your username (or email) and password. This usually comes in the form of a one time passcode, a push notification, or plugging in and tapping a hardware security key.
Common protocols Email and SMS MFA Email and SMS MFA are examples of the weaker MFA protocols. Email MFA is not great as whoever controls your email account can typically both reset your password and recieve your MFA verification."><meta property="og:type" content="article"><meta property="og:url" content="https://privsec.dev/knowledge/multi-factor-authentication/"><meta property="article:section" content="knowledge"><meta name=twitter:card content="summary"><meta name=twitter:title content="Multi-factor Authentication"><meta name=twitter:description content="Multi-factor authentication is a security mechanism that requires additional verification beyond your username (or email) and password. This usually comes in the form of a one time passcode, a push notification, or plugging in and tapping a hardware security key.
Common protocols Email and SMS MFA Email and SMS MFA are examples of the weaker MFA protocols. Email MFA is not great as whoever controls your email account can typically both reset your password and recieve your MFA verification."><script type=application/ld+json>{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":2,"name":"Knowledge Base","item":"https://privsec.dev/knowledge/"},{"@type":"ListItem","position":3,"name":"Multi-factor Authentication","item":"https://privsec.dev/knowledge/multi-factor-authentication/"}]}</script><script type=application/ld+json>{"@context":"https://schema.org","@type":"BlogPosting","headline":"Multi-factor Authentication","name":"Multi-factor Authentication","description":"Multi-factor authentication is a security mechanism that requires additional verification beyond your username (or email) and password. This usually comes in the form of a one time passcode, a push notification, or plugging in and tapping a hardware security key.\nCommon protocols Email and SMS MFA Email and SMS MFA are examples of the weaker MFA protocols. Email MFA is not great as whoever controls your email account can typically both reset your password and recieve your MFA verification.","keywords":["knowledge base","security"],"articleBody":"Multi-factor authentication is a security mechanism that requires additional verification beyond your username (or email) and password. This usually comes in the form of a one time passcode, a push notification, or plugging in and tapping a hardware security key.\nCommon protocols Email and SMS MFA Email and SMS MFA are examples of the weaker MFA protocols. Email MFA is not great as whoever controls your email account can typically both reset your password and recieve your MFA verification. SMS on the other hand is problematic due to the lack of any kind of encryption, making it vulnerable to sniffing. Sim swap attacks, if carried out successfully, will allow an attacker to recieve your one time passcode while locking you out of your own account. In certain cases,websites or services may also allow the user to reset their account login by calling them using the phone number used for MFA, which could be faked with a spoofed CallerID.\nOnly use these protocols when it is the only option you have, and be very careful with SMS MFA as it could actually worsen your security.\nPush Confirmations Push confirmation MFA is typically a notification being sent to an app on your phone asking you to confirm new account logins. This method is a lot better than SMS or email, since an attacker typically wouldnt be able to get these push notifications without having an already logged-in device.\nPush comfirmation in most cases rely on a third party provider like Duo. This means that trust is placed in a server that neither you nor your service provider control. A malicious push confirmation server could compromise your MFA or profile you based on which website and account you use with the service.\nEven if the push notification application and server is provided by first party as is the case with Microsoft login and Microsoft Authenticator, there is still a risk of you accidentally tapping on the confirmation button.\nTime-based One-time Password (TOTP) TOTP is one of the most common forms of MFA available. When you set up TOTP, you setup a “shared secret” with the service that you intend to use and store it in your authentication app.\nThe time-limited code is then derived from the shared secret and the current time. As the code is only valid for a short time, without access to the shared secret, an adversary cannot generate new codes.\nIf you have a Yubikey, you should store the “shared secrets” on the key itself using the Yubico Authenticator app. After the initial setup, the Yubico Authenticator will only expose the 6 digit code to the machine it is running on, but not the shared secret. Additional security can be set up by requiring touch confirmation, protecting digit codes not in used from a compromised operating system.\nUnlike WebAuthn, TOTP offers no protection against phishing or reuse attacks. If an adversary obtains a valid code from you, they may use it as many times as they like until it expires (generally 60 seconds + grace period).\nDespite of its short comings, TOTP is considered better and safer than Push Confirmations.\nYubico OTP Yubico OTP is an authentication protocol typically implemented in hardware security keys. When you decide to use Yubico OTP, the key will generate a public ID, private ID, and a Secret Key which is then uploaded to the Yubico OTP server.\nWhen logging into a website, all you need to do is to physically touch the security key. The security key will emulate a keyboard and print out a one-time password into the password field.\nThe service will then forward the one-time password to the Yubico OTP server for validation. A counter is incremented both on the key and Yubicos validation server. The OTP can only be used once, and when a successful authentication occurs, the counter is increased which prevents reuse of the OTP. Yubico provides a detailed document about the process.\nThe Yubico validation server is a cloud based service, and youre placing trust in Yubico that their server wont be used to bypass your MFA or profile you. The public ID associated with Yubico OTP is reused on every website and could be another avenue for third-parties to profile you. Like TOTP, Yubico OTP does not provide phishing resistance.\nYubico OTP is an inferior protocol compared to TOTP since TOTP does not need trust in a third party server and most security keys that support Yubico OTP (namely the Yubikey and OnlyKey) supports TOTP anyway. Yubico OTP is still better than Push Confirmation, however.\nFIDO (Fast IDentity Online) FIDO includes a number of standards, first there was U2F and then later FIDO2 which includes the web standard WebAuthn.\nU2F and FIDO2 refer to the Client to Authenticator Protocol, which is the protocol between the security key and the computer, such as a laptop or phone. It complements WebAuthn which is the component used to authenticate with the website (the “Relying Party”) youre trying to log in on.\nWebAuthn is the most secure and private form of second factor authentication. While the authentication experience is similar to Yubico OTP, the key does not print out a one-time password and validate with a third-party server. Instead, it uses public key cryptography for authentication.\nWhen you create an account, the public key is sent to the service, then when you log in, the service will require you to “sign” some data with your private key. The benefit of this is that no password data is ever stored by the service, so there is nothing for an adversary to steal.\nFIDO2 and WebAuthn have superior security and privacy properties when compared to any MFA methods.\nTypically for web services it is used with WebAuthn which is a part of the W3C recommendations. It uses public key authentication and is more secure than shared secrets used in Yubico OTP and TOTP methods, as it includes the origin name (usually, the domain name) during authentication. Attestation is provided to protect you from phishing attacks, as it helps you to determine that you are using the authentic service and not a fake copy.\nUnlike Yubico OTP, WebAuthn does not use any public ID, so the key is not identifiable across different websites. It also does not use any third-party cloud server for authentication. All communication is completed between the key and the website you are logging into. FIDO also uses a counter which is incremented upon use in order to prevent session reuse and cloned keys.\nIf a website or service supports WebAuthn for the authentication, it is highly recommended that you use it over any other form of MFA.\nNotes Initial Set Up When buying a security key, it is important that you change the default credentials, set up password protection for the key, and enable touch confirmation if your key supports it. Products such as the YubiKey have multiple interfaces with separate credentials for each one of them, so you should go over each interface and set up protection as well.\nBackups You should always have backups for your MFA method. Hardware security keys can get lost, stolen or simply stop working over time. It is recommended that you have a pair of hardware security keys with the same access to your accounts instead of just one.\nWhen using TOTP with an authenticator app, be sure to back up your recovery keys or the app itself, or copy the “shared secrets” to another instance of the app on a different phone or to an encrypted container (e.g. VeraCrypt).\n","wordCount":"1259","inLanguage":"en","datePublished":"0001-01-01T00:00:00Z","dateModified":"0001-01-01T00:00:00Z","author":{"@type":"Person","name":"Tommy"},"mainEntityOfPage":{"@type":"WebPage","@id":"https://privsec.dev/knowledge/multi-factor-authentication/"},"publisher":{"@type":"Organization","name":"PrivSec.dev","logo":{"@type":"ImageObject","url":"https://privsec.dev/%3Clink%20/%20abs%20url%3E"}}}</script></head><body class=dark id=top><script>localStorage.getItem("pref-theme")==="light"&&document.body.classList.remove("dark")</script><header class=header><nav class=nav><div class=logo><a href=https://privsec.dev accesskey=h title="PrivSec.dev (Alt + H)">PrivSec.dev</a><div class=logo-switches><button id=theme-toggle accesskey=t title="(Alt + T)"><svg id="moon" xmlns="http://www.w3.org/2000/svg" width="24" height="18" viewBox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12.79A9 9 0 1111.21 3 7 7 0 0021 12.79z"/></svg><svg id="sun" xmlns="http://www.w3.org/2000/svg" width="24" height="18" viewBox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="5"/><line x1="12" y1="1" x2="12" y2="3"/><line x1="12" y1="21" x2="12" y2="23"/><line x1="4.22" y1="4.22" x2="5.64" y2="5.64"/><line x1="18.36" y1="18.36" x2="19.78" y2="19.78"/><line x1="1" y1="12" x2="3" y2="12"/><line x1="21" y1="12" x2="23" y2="12"/><line x1="4.22" y1="19.78" x2="5.64" y2="18.36"/><line x1="18.36" y1="5.64" x2="19.78" y2="4.22"/></svg></button></div></div><ul id=menu><li><a href=https://privsec.dev/knowledge/ title="Knowledge Base"><span>Knowledge Base</span></a></li><li><a href=https://privsec.dev/os/ title="Operating Systems"><span>Operating Systems</span></a></li><li><a href=https://privsec.dev/software/ title=Software><span>Software</span></a></li><li><a href=https://privsec.dev/providers/ title=Providers><span>Providers</span></a></li></ul></nav></header><main class=main><article class=post-single><header class=post-header><div class=breadcrumbs><a href=https://privsec.dev>Home</a>&nbsp;»&nbsp;<a href=https://privsec.dev/knowledge/>Knowledge Base</a></div><h1 class=post-title>Multi-factor Authentication</h1><div class=post-meta>6 min&nbsp;·&nbsp;1259 words&nbsp;·&nbsp;Tommy&nbsp;|&nbsp;<a href=https://github.com/PrivSec-dev/privsec.dev/content/knowledge/Multi-factor%20Authentication.md rel="noopener noreferrer" target=_blank>Suggest Changes</a></div></header><div class=toc><details><summary accesskey=c title="(Alt + C)"><span class=details>Table of Contents</span></summary><div class=inner><ul><li><a href=#common-protocols aria-label="Common protocols">Common protocols</a><ul><li><a href=#email-and-sms-mfa aria-label="Email and SMS MFA">Email and SMS MFA</a></li><li><a href=#push-confirmations aria-label="Push Confirmations">Push Confirmations</a></li><li><a href=#time-based-one-time-password-totp aria-label="Time-based One-time Password (TOTP)">Time-based One-time Password (TOTP)</a></li><li><a href=#yubico-otp aria-label="Yubico OTP">Yubico OTP</a></li><li><a href=#fido-fast-identity-online aria-label="FIDO (Fast IDentity Online)">FIDO (Fast IDentity Online)</a></li></ul></li><li><a href=#notes aria-label=Notes>Notes</a><ul><li><a href=#initial-set-up aria-label="Initial Set Up">Initial Set Up</a></li><li><a href=#backups aria-label=Backups>Backups</a></li></ul></li></ul></div></details></div><div class=post-content><p><strong>Multi-factor authentication</strong> is a security mechanism that requires additional verification beyond your username (or email) and password. This usually comes in the form of a one time passcode, a push notification, or plugging in and tapping a hardware security key.</p><h2 id=common-protocols>Common protocols<a hidden class=anchor aria-hidden=true href=#common-protocols>#</a></h2><h3 id=email-and-sms-mfa>Email and SMS MFA<a hidden class=anchor aria-hidden=true href=#email-and-sms-mfa>#</a></h3><p>Email and SMS MFA are examples of the weaker MFA protocols. Email MFA is not great as whoever controls your email account can typically both reset your password and recieve your MFA verification. SMS on the other hand is problematic due to the lack of any kind of encryption, making it vulnerable to sniffing. <a href=https://en.wikipedia.org/wiki/SIM_swap_scam>Sim swap</a> attacks, if carried out successfully, will allow an attacker to recieve your one time passcode while locking you out of your own account. In certain cases,websites or services may also allow the user to reset their account login by calling them using the phone number used for MFA, which could be faked with a <a href=https://en.wikipedia.org/wiki/Caller_ID_spoofing>spoofed CallerID</a>.</p><p>Only use these protocols when it is the only option you have, and be very careful with SMS MFA as it could actually worsen your security.</p><h3 id=push-confirmations>Push Confirmations<a hidden class=anchor aria-hidden=true href=#push-confirmations>#</a></h3><p>Push confirmation MFA is typically a notification being sent to an app on your phone asking you to confirm new account logins. This method is a lot better than SMS or email, since an attacker typically wouldn&rsquo;t be able to get these push notifications without having an already logged-in device.</p><p>Push comfirmation in most cases rely on a third party provider like <a href=https://duo.com/>Duo</a>. This means that trust is placed in a server that neither you nor your service provider control. A malicious push confirmation server could compromise your MFA or profile you based on which website and account you use with the service.</p><p>Even if the push notification application and server is provided by first party as is the case with Microsoft login and <a href=https://www.microsoft.com/en-us/security/mobile-authenticator-app>Microsoft Authenticator</a>, there is still a risk of you accidentally tapping on the confirmation button.</p><h3 id=time-based-one-time-password-totp>Time-based One-time Password (TOTP)<a hidden class=anchor aria-hidden=true href=#time-based-one-time-password-totp>#</a></h3><p>TOTP is one of the most common forms of MFA available. When you set up TOTP, you setup a &ldquo;<a href=https://en.wikipedia.org/wiki/Shared_secret>shared secret</a>&rdquo; with the service that you intend to use and store it in your authentication app.</p><p>The time-limited code is then derived from the shared secret and the current time. As the code is only valid for a short time, without access to the shared secret, an adversary cannot generate new codes.</p><p>If you have a <a href=https://www.yubico.com/>Yubikey</a>, you should store the &ldquo;shared secrets&rdquo; on the key itself using the <a href=https://www.yubico.com/products/yubico-authenticator/>Yubico Authenticator</a> app. After the initial setup, the Yubico Authenticator will only expose the 6 digit code to the machine it is running on, but not the shared secret. Additional security can be set up by requiring touch confirmation, protecting digit codes not in used from a compromised operating system.</p><p>Unlike <a href=#fido-fast-identity-online>WebAuthn</a>, TOTP offers no protection against <a href=https://en.wikipedia.org/wiki/Phishing>phishing</a> or reuse attacks. If an adversary obtains a valid code from you, they may use it as many times as they like until it expires (generally 60 seconds + grace period).</p><p>Despite of its short comings, TOTP is considered better and safer than Push Confirmations.</p><h3 id=yubico-otp>Yubico OTP<a hidden class=anchor aria-hidden=true href=#yubico-otp>#</a></h3><p>Yubico OTP is an authentication protocol typically implemented in hardware security keys. When you decide to use Yubico OTP, the key will generate a public ID, private ID, and a Secret Key which is then uploaded to the Yubico OTP server.</p><p>When logging into a website, all you need to do is to physically touch the security key. The security key will emulate a keyboard and print out a one-time password into the password field.</p><p>The service will then forward the one-time password to the Yubico OTP server for validation. A counter is incremented both on the key and Yubico&rsquo;s validation server. The OTP can only be used once, and when a successful authentication occurs, the counter is increased which prevents reuse of the OTP. Yubico provides a <a href=https://developers.yubico.com/OTP/OTPs_Explained.html>detailed document</a> about the process.</p><p><img loading=lazy src=/yubico-otp.png alt="Yubico OTP"></p><p>The Yubico validation server is a cloud based service, and you&rsquo;re placing trust in Yubico that their server won&rsquo;t be used to bypass your MFA or profile you. The public ID associated with Yubico OTP is reused on every website and could be another avenue for third-parties to profile you. Like TOTP, Yubico OTP does not provide phishing resistance.</p><p>Yubico OTP is an inferior protocol compared to TOTP since TOTP does not need trust in a third party server and most security keys that support Yubico OTP (namely the Yubikey and OnlyKey) supports TOTP anyway. Yubico OTP is still better than Push Confirmation, however.</p><h3 id=fido-fast-identity-online>FIDO (Fast IDentity Online)<a hidden class=anchor aria-hidden=true href=#fido-fast-identity-online>#</a></h3><p><a href=https://en.wikipedia.org/wiki/FIDO_Alliance>FIDO</a> includes a number of standards, first there was U2F and then later <a href=https://en.wikipedia.org/wiki/FIDO2_Project>FIDO2</a> which includes the web standard <a href=https://en.wikipedia.org/wiki/WebAuthn>WebAuthn</a>.</p><p>U2F and FIDO2 refer to the <a href=https://en.wikipedia.org/wiki/Client_to_Authenticator_Protocol>Client to Authenticator Protocol</a>, which is the protocol between the security key and the computer, such as a laptop or phone. It complements WebAuthn which is the component used to authenticate with the website (the &ldquo;Relying Party&rdquo;) you&rsquo;re trying to log in on.</p><p>WebAuthn is the most secure and private form of second factor authentication. While the authentication experience is similar to Yubico OTP, the key does not print out a one-time password and validate with a third-party server. Instead, it uses <a href=https://en.wikipedia.org/wiki/Public-key_cryptography>public key cryptography</a> for authentication.</p><p>When you create an account, the public key is sent to the service, then when you log in, the service will require you to &ldquo;sign&rdquo; some data with your private key. The benefit of this is that no password data is ever stored by the service, so there is nothing for an adversary to steal.</p><div style=position:relative;padding-bottom:56.25%;height:0;overflow:hidden><iframe src=https://www.youtube-nocookie.com/embed/aMo4ZlWznao style=position:absolute;top:0;left:0;width:100%;height:100%;border:0 allowfullscreen title="YouTube Video"></iframe></div><p>FIDO2 and WebAuthn have superior security and privacy properties when compared to any MFA methods.</p><p>Typically for web services it is used with WebAuthn which is a part of the <a href=https://en.wikipedia.org/wiki/World_Wide_Web_Consortium#W3C_recommendation_(REC)>W3C recommendations</a>. It uses public key authentication and is more secure than shared secrets used in Yubico OTP and TOTP methods, as it includes the origin name (usually, the domain name) during authentication. Attestation is provided to protect you from phishing attacks, as it helps you to determine that you are using the authentic service and not a fake copy.</p><p>Unlike Yubico OTP, WebAuthn does not use any public ID, so the key is <strong>not</strong> identifiable across different websites. It also does not use any third-party cloud server for authentication. All communication is completed between the key and the website you are logging into. FIDO also uses a counter which is incremented upon use in order to prevent session reuse and cloned keys.</p><p>If a website or service supports WebAuthn for the authentication, it is highly recommended that you use it over any other form of MFA.</p><h2 id=notes>Notes<a hidden class=anchor aria-hidden=true href=#notes>#</a></h2><h3 id=initial-set-up>Initial Set Up<a hidden class=anchor aria-hidden=true href=#initial-set-up>#</a></h3><p>When buying a security key, it is important that you change the default credentials, set up password protection for the key, and enable touch confirmation if your key supports it. Products such as the YubiKey have multiple interfaces with separate credentials for each one of them, so you should go over each interface and set up protection as well.</p><h3 id=backups>Backups<a hidden class=anchor aria-hidden=true href=#backups>#</a></h3><p>You should always have backups for your MFA method. Hardware security keys can get lost, stolen or simply stop working over time. It is recommended that you have a pair of hardware security keys with the same access to your accounts instead of just one.</p><p>When using TOTP with an authenticator app, be sure to back up your recovery keys or the app itself, or copy the &ldquo;shared secrets&rdquo; to another instance of the app on a different phone or to an encrypted container (e.g. <a href=../encryption.md#veracrypt>VeraCrypt</a>).</p></div><footer class=post-footer><ul class=post-tags><li><a href=https://privsec.dev/tags/knowledge-base/>knowledge base</a></li><li><a href=https://privsec.dev/tags/security/>security</a></li></ul></footer></article></main><footer class=footer><span>&copy; 2022 <a href=https://privsec.dev>PrivSec.dev</a></span>
<span>Powered by
<a href=https://gohugo.io/ rel="noopener noreferrer" target=_blank>Hugo</a> &
<a href=https://github.com/adityatelange/hugo-PaperMod/ rel=noopener target=_blank>PaperMod</a></span></footer><a href=#top aria-label="go to top" title="Go to Top (Alt + G)" class=top-link id=top-link accesskey=g><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 12 6" fill="currentcolor"><path d="M12 6H0l6-6z"/></svg></a><script>let menu=document.getElementById("menu");menu&&(menu.scrollLeft=localStorage.getItem("menu-scroll-position"),menu.onscroll=function(){localStorage.setItem("menu-scroll-position",menu.scrollLeft)}),document.querySelectorAll('a[href^="#"]').forEach(e=>{e.addEventListener("click",function(e){e.preventDefault();var t=this.getAttribute("href").substr(1);window.matchMedia("(prefers-reduced-motion: reduce)").matches?document.querySelector(`[id='${decodeURIComponent(t)}']`).scrollIntoView():document.querySelector(`[id='${decodeURIComponent(t)}']`).scrollIntoView({behavior:"smooth"}),t==="top"?history.replaceState(null,null," "):history.pushState(null,null,`#${t}`)})})</script><script>var mybutton=document.getElementById("top-link");window.onscroll=function(){document.body.scrollTop>800||document.documentElement.scrollTop>800?(mybutton.style.visibility="visible",mybutton.style.opacity="1"):(mybutton.style.visibility="hidden",mybutton.style.opacity="0")}</script><script>document.getElementById("theme-toggle").addEventListener("click",()=>{document.body.className.includes("dark")?(document.body.classList.remove("dark"),localStorage.setItem("pref-theme","light")):(document.body.classList.add("dark"),localStorage.setItem("pref-theme","dark"))})</script><script>document.querySelectorAll("pre > code").forEach(e=>{const n=e.parentNode.parentNode,t=document.createElement("button");t.classList.add("copy-code"),t.innerHTML="copy";function s(){t.innerHTML="copied!",setTimeout(()=>{t.innerHTML="copy"},2e3)}t.addEventListener("click",t=>{if("clipboard"in navigator){navigator.clipboard.writeText(e.textContent),s();return}const n=document.createRange();n.selectNodeContents(e);const o=window.getSelection();o.removeAllRanges(),o.addRange(n);try{document.execCommand("copy"),s()}catch{}o.removeRange(n)}),n.classList.contains("highlight")?n.appendChild(t):n.parentNode.firstChild==n||(e.parentNode.parentNode.parentNode.parentNode.parentNode.nodeName=="TABLE"?e.parentNode.parentNode.parentNode.parentNode.parentNode.appendChild(t):e.parentNode.appendChild(t))})</script></body></html>