summaryrefslogtreecommitdiff
path: root/web/index.hoon
diff options
context:
space:
mode:
authorpolwex <polwex@sortug.com>2025-06-22 13:40:29 +0700
committerpolwex <polwex@sortug.com>2025-06-22 13:40:29 +0700
commit4e2a84761b95a29c02c77c575810ab49f2af7335 (patch)
treeb91c169f906797cc07d784ee07671f5516f21d68 /web/index.hoon
parent6dccba9bb5100329209ad01732f9d63f4c4fb43b (diff)
metamask login pretty much done
Diffstat (limited to 'web/index.hoon')
-rw-r--r--web/index.hoon457
1 files changed, 9 insertions, 448 deletions
diff --git a/web/index.hoon b/web/index.hoon
index 9aede2e..4342d84 100644
--- a/web/index.hoon
+++ b/web/index.hoon
@@ -1,291 +1,11 @@
+/= sigil-html /web/sigil/sigil
|_ bowl:gall
-++ auth-styling
- '''
- @import url("https://rsms.me/inter/inter.css");
- @font-face {
- font-family: "Source Code Pro";
- src: url("https://storage.googleapis.com/media.urbit.org/fonts/scp-regular.woff");
- font-weight: 400;
- font-display: swap;
- }
- :root {
- --red-soft: #FFEFEC;
- --red: #FF6240;
- --gray-100: #E5E5E5;
- --gray-400: #999999;
- --gray-800: #333333;
- --white: #FFFFFF;
- }
- html {
- font-family: Inter, sans-serif;
- height: 100%;
- margin: 0;
- width: 100%;
- background: var(--white);
- color: var(--gray-800);
- -webkit-font-smoothing: antialiased;
- line-height: 1.5;
- font-size: 16px;
- font-weight: 600;
- display: flex;
- flex-flow: row nowrap;
- justify-content: center;
- }
- body {
- display: flex;
- flex-flow: column nowrap;
- justify-content: center;
- max-width: 300px;
- padding: 1rem;
- width: 100%;
- }
- body.local #eauth,
- body.eauth #local {
- display: none;
- min-height: 100%;
- }
- #eauth input {
- /*NOTE dumb hack to get approx equal height with #local */
- margin-bottom: 15px;
- }
- body nav {
- background: var(--gray-100);
- border-radius: 2rem;
- display: flex;
- justify-content: space-around;
- overflow: hidden;
- margin-bottom: 1rem;
- }
- body nav div {
- width: 50%;
- padding: 0.5rem 1rem;
- text-align: center;
- cursor: pointer;
- }
- body.local nav div.local,
- body.eauth nav div.eauth {
- background: var(--gray-800);
- color: var(--white);
- cursor: default;
- }
- nav div.local {
- border-right: none;
- border-top-right-radius: 0;
- border-bottom-right-radius: 0;
- }
- nav div.eauth {
- border-left: none;
- border-top-left-radius: 0;
- border-bottom-left-radius: 0;
- }
- body > *,
- form > input {
- width: 100%;
- }
- form {
- display: flex;
- flex-flow: column;
- align-items: flex-start;
- }
- input {
- background: var(--gray-100);
- border: 2px solid transparent;
- padding: 0.5rem;
- border-radius: 0.5rem;
- font-size: inherit;
- color: var(--gray-800);
- box-shadow: none;
- width: 100%;
- }
- input:disabled {
- background: var(--gray-100);
- color: var(--gray-400);
- }
- input:focus {
- outline: none;
- background: var(--white);
- border-color: var(--gray-400);
- }
- input:invalid:not(:focus) {
- background: var(--red-soft);
- border-color: var(--red);
- outline: none;
- color: var(--red);
- }
- button[type=submit] {
- margin-top: 1rem;
- }
- button[type=submit], a.button {
- font-size: 1rem;
- padding: 0.5rem 1rem;
- border-radius: 0.5rem;
- background: var(--gray-800);
- color: var(--white);
- border: none;
- font-weight: 600;
- text-decoration: none;
- }
- input:invalid ~ button[type=submit] {
- border-color: currentColor;
- background: var(--gray-100);
- color: var(--gray-400);
- pointer-events: none;
- }
- span.guest, span.guest a {
- color: var(--gray-400);
- }
- span.failed {
- display: flex;
- flex-flow: row nowrap;
- height: 1rem;
- align-items: center;
- margin-top: 0.875rem;
- color: var(--red);
- }
- span.failed svg {
- height: 1rem;
- margin-right: 0.25rem;
- }
- span.failed path {
- fill: transparent;
- stroke-width: 2px;
- stroke-linecap: round;
- stroke: currentColor;
- }
- .mono {
- font-family: 'Source Code Pro', monospace;
- }
- @media all and (prefers-color-scheme: dark) {
- :root {
- --white: #000000;
- --gray-800: #E5E5E5;
- --gray-400: #808080;
- --gray-100: #333333;
- --red-soft: #7F1D1D;
- }
- }
- @media screen and (min-width: 30em) {
- html {
- font-size: 14px;
- }
- }
- '''
++ favicon %+
weld "<svg width='10' height='10' viewBox='0 0 10 10' xmlns='http://www.w3.org/2000/svg'>"
"<circle r='3.09' cx='5' cy='5' /></svg>"
-++ landscape ^- manx
-=/ eauth=(unit ?) [~ %|]
-=/ failed=? .n
-=/ identity=identity:eyre [%ours ~]
-=/ redirect-url=(unit @t) ~
-=/ redirect-str ?~(redirect-url "" (trip u.redirect-url))
- ;html
- ;head
- ;meta(charset "utf-8");
- ;meta(name "viewport", content "width=device-width, initial-scale=1, shrink-to-fit=no");
- ;link(rel "icon", type "image/svg+xml", href (weld "data:image/svg+xml;utf8," favicon));
- ;title:"Urbit"
- ;style:"{(trip auth-styling)}"
- ;style:"{?^(eauth "" "nav \{ display: none; }")}"
- ;script:"our = '{(scow %p our)}';"
- ;script:'''
- let name, pass;
- function setup(isEauth) {
- name = document.getElementById('name');
- pass = document.getElementById('pass');
- if (isEauth) goEauth(); else goLocal();
- }
- function goLocal() {
- document.body.className = 'local';
- pass.focus();
- }
- function goEauth() {
- document.body.className = 'eauth';
- name.focus();
- }
- function doEauth() {
- if (name.value == our) {
- event.preventDefault();
- goLocal();
- }
- }
- '''
- ==
- ;body
- =class "{?:(=(`& eauth) "eauth" "local")}"
- =onload "setup({?:(=(`& eauth) "true" "false")})"
- ;div#local
- ;p:"Urbit ID"
- ;input(value "{(scow %p our)}", disabled "true", class "mono");
- ;+ ?: =(%ours -.identity)
- ;div
- ;p:"Already authenticated"
- ;a.button/"{(trip (fall redirect-url '/'))}":"Continue"
- ==
- ;form(action "/~/login", method "post", enctype "application/x-www-form-urlencoded")
- ;p:"Access Key"
- ;input
- =type "password"
- =name "password"
- =id "pass"
- =placeholder "sampel-ticlyt-migfun-falmel"
- =class "mono"
- =required "true"
- =minlength "27"
- =maxlength "27"
- =pattern "((?:[a-z]\{6}-)\{3}(?:[a-z]\{6}))";
- ;input(type "hidden", name "redirect", value redirect-str);
- ;+ ?. failed ;span;
- ;span.failed
- ;svg(xmlns "http://www.w3.org/2000/svg", viewBox "0 0 16 16")
- ;path(d "m8 8 4-4M8 8 4 4m4 4-4 4m4-4 4 4");
- ==
- Key is incorrect
- ==
- ;button(type "submit"):"Continue"
- ==
- ==
- ;div#eauth
- ;form(action "/~/login", method "post", onsubmit "return doEauth()")
- ;p:"Urbit ID Metamask Login"
- ;input.mono
- =name "name"
- =id "name"
- =placeholder "{(scow %p our)}"
- =required "true"
- =minlength "4"
- =maxlength "57"
- =pattern "~((([a-z]\{6})\{1,2}-\{0,2})+|[a-z]\{3})";
- ;p
- ; You will be redirected to your own web interface to authorize
- ; logging in to
- ;span.mono:"{(scow %p our)}"
- ; .
- ==
- ;input(type "hidden", name "redirect", value redirect-str);
- ;button(name "eauth", type "submit"):"Continue"
- ==
- ==
- ;* ?: ?=(%ours -.identity) ~
- =+ as="proceed as{?:(?=(%fake -.identity) " guest" "")}"
- ;+ ;span.guest.mono
- ; Or try to
- ;a/"{(trip (fall redirect-url '/'))}":"{as}"
- ; .
- ==
- ==
- ;script:'''
- var failSpan = document.querySelector('.failed');
- if (failSpan) {
- document.querySelector("input[type=password]")
- .addEventListener('keyup', function (event) {
- failSpan.style.display = 'none';
- });
- }
- '''
- ==
+
++ $
-=/ redirect-str "/forum"
+=/ sigil (sigil-html src)
;html
;head
;meta(charset "utf-8");
@@ -294,172 +14,13 @@
==
;body
;main#login-page.white
- ;h1.tc:"Login"
- ;form#form(action "/~/login", method "POST")
- ;h2.tc: Urbit OS (Azimuth via Arvo)
- ;input.mono(type "text")
- =name "name"
- =id "name"
- =placeholder "~sampel-palnet"
- =required "true"
- =minlength "4"
- =maxlength "14"
- =pattern "~((([a-z]\{6})\{1,2}-\{0,2})+|[a-z]\{3})";
- ;input(type "hidden", name "redirect", value redirect-str);
- ;button(name "eauth", type "submit"):"Login via Ship »"
- ==
- ;button(id "mauth"):"Login via 🦊MetaMask »"
- ;script(type "module"):"{metamask-script}"
- :: ;script(type "importmap"):"{import-script}"
- ;div(id "wallet-points");
- ;div(id "spinner");
- ;h2.tc: Join the Urbit Network
- ;div.tc.nudge
- ;a.button/"https://redhorizon.com/join/2d55b768-a5f4-45cf-a4e5-a4302e05a1f9":"Get Urbit ID »"
- ;p:"If you don't have an Urbit ID, get one for free from Red Horizon."
- ==
+ ;h1.tc:"Henlo"
+ ;p:"You are logged"
+ ;+ sigil
+ ==
+ ;form(action "/zodiac/logout", method "get")
+ ;button(id "logout-button", type "submit"):"Logout"
==
==
==
-++ import-script
- ^~
- %- trip
-'''
- {"imports": {
- "ethers": "/node_modules/ethers/"
- }}
-'''
-++ metamask-script
- ^~
- %- trip
-'''
- import { ethers } from "https://cdnjs.cloudflare.com/ajax/libs/ethers/6.7.0/ethers.min.js";
-
-
- const AZIMUTH_ADDRESS = "0x223c067F8CF28ae173EE5CafEa60cA44C335fecB";
- const AZIMUTH_ABI_MINI = [{
- "constant": true,
- "inputs": [{ "name": "_whose", "type": "address" }],
- "name": "getOwnedPoints",
- "outputs": [{ "name": "ownedPoints", "type": "uint32[]" }],
- "payable": false,
- "stateMutability": "view",
- "type": "function"
- }];
-
- window.addEventListener("DOMContentLoaded", () => {
-
- const spinner = document.getElementById("spinner");
- const pointsDiv = document.getElementById("wallet-points");
- const metamaskButton = document.getElementById("mauth");
- metamaskButton.addEventListener("click", (event) => {
- event.preventDefault(); // Prevent the form from submitting the default way
- metamaskButton.disabled = true;
- getProvider().then(provider => {
- getPoints(provider).then(points => {
- console.log({points})
- points.forEach(point => {
- const div = document.createElement("div");
- div.innerText = `${point}`;
- div.addEventListener("click", e => {
- if (spinner.innerText) return
- spinner.innerText = "Logging in..."
- metamaskLogin(provider.address, point).then(res => {
- spinner.innerText = `${res}`
- })
- })
- pointsDiv.appendChild(div);
- })
- // why doesn't this work wtf
- // for (const points of points){
- // console.log({point})
- // }
-
- }).catch(e => {
- metamaskButton.disabled = false;
- })
- })
- });
- });
-
- async function fetchSecret() {
- try {
- const response = await fetch('/forum/metamask');
- if (response.ok) {
- const data = await response.json();
- return data.challenge;
- } else {
- throw new Error('Failed to retrieve secret');
- }
- } catch (error) {
- console.error('Error fetching secret:', error);
- }
- }
-
-
- async function getProvider(){
- if (typeof window.ethereum !== 'undefined') {
- try {
- const accounts = await window.ethereum.request({ method: "eth_requestAccounts" });
- const account = accounts[0];
- console.log("logged with metamask on account", account);
- const provider = new ethers.BrowserProvider(window.ethereum)
- const t1 = await provider.getBalance(account)
- console.log({t1})
- const signer = await provider.getSigner();
- console.log({provider, signer})
- return signer
-
- } catch (error) {
- alert("MetaMask initialization failed");
- }
- } else {
- alert("MetaMask is not installed. Please install it to continue.");
- }
-
- }
-
- async function metamaskLogin(account, point){
- // Fetch the secret from the server
- const secret = await fetchSecret();
- console.log({secret});
- const signature = await window.ethereum.request({
- method: "personal_sign",
- params: [secret, account],
- });
-
- const response = await fetch('/forum/auth', {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json'
- },
- body: JSON.stringify({
- who: point,
- secret: secret,
- address: account,
- signature: signature
- }),
- });
-
- if (response.ok) {
- // location.reload();
- // window.location.replace('/forum');
- return "done!"
- } else {
- alert("Login failed. Please try again.");
- }
-
- }
-
- async function getPoints(provider){
- const address = provider.address;
- const contract = new ethers.Contract(
- AZIMUTH_ADDRESS,
- AZIMUTH_ABI_MINI,
- provider,
- );
- const res = await contract.getOwnedPoints(address);
- return res.toArray();
- }
-'''
--