<h1>alu.bz</h1>
<nav>
<button id="connect" class="text-button">Connect Wallet</button>
- <button>
+ <button id="info-button">
<svg role="img" aria-labelledby="info" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<title id="info">About this site</title>
<circle cx="12" cy="12" r="10"></circle>
<output id="status" name="status"></output>
</form>
+ <dialog id="info-dialog">
+ <form method="dialog">
+ <button>
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+ <line x1="18" y1="6" x2="6" y2="18"></line>
+ <line x1="6" y1="6" x2="18" y2="18"></line>
+ </svg>
+ </button>
+ </form>
+
+ <h1>Info</h1>
+ <h2>What is this?</h2>
+ <p>This site is a proof of concept <a href="https://en.wikipedia.org/wiki/URL_shortening">short link service</a> that uses the <a href="https://ethereum.org/">Ethereum blockchain</a> for its authorization backend.</p>
+ <p>It's free to create a short link with a random four character path.</p>
+ <p>Users that hold a special access <a href="https://en.wikipedia.org/wiki/Non-fungible_token"><abbr title="Non-Fungible Token">NFT</abbr></a> may create custom short paths.</p>
+ <p>Custom short paths may be any combination of alphanumeric characters, hyphens, and underscores, with a maximum length of 80.</p>
+ <h2>Why?</h2>
+ <p>Rolling your own auth is hard to get right. And integrating with a third-party auth provider creates complexity.</p>
+ <p>Using Ethereum for authorization strikes a good balance between minimizing complexity and maintaining security.</p>
+ <p>This website is an example minimal viable product that uses Ethereum for access control.</p>
+ <h2>How does it work?</h2>
+ <p>Many web3 projects use a frontend framework like <a href="https://docs.ethers.io/v5/">ethers.js</a> or <a href="https://web3js.readthedocs.io/en/v1.8.0/">web3.js</a> to integrate with Ethereum.</p>
+ <p>To demonstrate the minimum required code, this project's frontend is implemented entirely in vanilla HTML, CSS, and JavaScript with no framework. The only integration is with <a href="https://metamask.io/">MetaMask</a> to get user <a href="https://ethereum.org/en/glossary/#digital-signatures">signatures</a> for authorization.</p>
+ <p>The backend is a serverless <a href="https://workers.cloudflare.com/">Cloudflare Worker</a>, also written in vanilla JavaScript. The code to verify signatures on the backend was extracted from ethers.js.</p>
+ <h2>Source code</h2>
+ <p><a href="https://github.com/ardislu/alu.bz">Click here</a> to view this project's source code on GitHub.</p>
+ <p>The code for both the frontend and the backend is available in the GitHub repository.</p>
+ <h2>Disclaimer</h2>
+ <p><strong>Do not rely on this service for permanent links.</strong></p>
+ <p>This is a personal project. Short links may be changed or deleted at any time.</p>
+ </dialog>
+
<dialog id="notification">
<form method="dialog">
<p>MetaMask must be installed to Connect Wallet.</p>
let currentAccount = null;
+const infoButton = document.getElementById('info-button');
+const infoDialog = document.getElementById('info-dialog');
const connectButton = document.getElementById('connect');
const shortUrlInput = document.getElementById('short-url');
const shortUrlAside = document.getElementById('short-url-aside');
}
});
-form.addEventListener('submit', handleSubmit);
\ No newline at end of file
+form.addEventListener('submit', handleSubmit);
+
+infoButton.addEventListener('click', () => {
+ infoDialog.showModal();
+});
\ No newline at end of file
}
dialog {
+ background: var(--primary-complement);
+}
+
+dialog button {
+ align-self: center;
+}
+
+#notification {
position: fixed;
bottom: 16px;
- background: var(--primary-complement);
border-radius: 16px;
border: 2px solid var(--primary-strongest);
}
-dialog>form {
+#notification>form {
flex-direction: row;
}
-dialog button {
- align-self: center;
+#info-dialog {
+ box-sizing: border-box;
+ position: fixed;
+ top: 0;
+ left: 0;
+ inline-size: 100%;
+ block-size: 100%;
+ max-inline-size: initial;
+ max-block-size: initial;
+ margin: 0;
+ border: none;
+}
+
+#info-dialog button {
+ position: fixed;
+ top: 16px;
+ right: 16px;
+ filter: brightness(115%);
+}
+
+@media (min-width: 34.375rem) {
+ #info-dialog {
+ inline-size: min(100% - 32px, 960px);
+ block-size: fit-content;
+ max-block-size: calc(100% - 32px);
+ margin-inline: auto;
+ margin-block-start: 16px;
+ border-radius: 16px;
+ border: 2px solid var(--primary-strongest);
+ }
+
+ #info-dialog button {
+ position: absolute;
+ }
+}
+
+#info-dialog>form * {
+ margin: 0;
}
#connect {