summaryrefslogtreecommitdiff
path: root/web
diff options
context:
space:
mode:
Diffstat (limited to 'web')
-rw-r--r--web/index.hoon8
-rw-r--r--web/login.hoon311
-rw-r--r--web/router.hoon159
3 files changed, 117 insertions, 361 deletions
diff --git a/web/index.hoon b/web/index.hoon
index 4342d84..c9aa43a 100644
--- a/web/index.hoon
+++ b/web/index.hoon
@@ -1,5 +1,5 @@
/= sigil-html /web/sigil/sigil
-|_ bowl:gall
+|_ [bowl:gall base-slug=tape]
++ 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>"
@@ -18,7 +18,11 @@
;p:"You are logged"
;+ sigil
==
- ;form(action "/zodiac/logout", method "get")
+ ;form(action "/{base-slug}/poke", method "get")
+ ;button(type "submit"):"Test"
+ ==
+
+ ;form(action "/{base-slug}/logout", method "get")
;button(id "logout-button", type "submit"):"Logout"
==
==
diff --git a/web/login.hoon b/web/login.hoon
index b4b1084..aa1d57d 100644
--- a/web/login.hoon
+++ b/web/login.hoon
@@ -1,291 +1,8 @@
-|_ 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;
- }
- }
- '''
+|_ [bowl:gall desk=tape redirect-str=tape]
++ 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"
;html
;head
;meta(charset "utf-8");
@@ -294,7 +11,7 @@
==
;body
;main#login-page.white
- ;h1.tc:"Zodiac Login"
+ ;h1.tc:"Login"
;button(id "mauth"):"Login via 🦊MetaMask »"
;script(type "module"):"{metamask-script}"
:: ;script(type "importmap"):"{import-script}"
@@ -316,8 +33,17 @@
"ethers": "/node_modules/ethers/"
}}
'''
+++ fetch-urls ^- tape
+"""
+const sigilUrl = "/{desk}/sigil/";
+const secretUrl= "/{desk}/metamask";
+const authUrl= "/{desk}/auth";
+const redirectUrl = "{redirect-str}";
+
+"""
++ metamask-script
^~
+ %+ weld fetch-urls
%- trip
'''
import { ethers } from "https://cdnjs.cloudflare.com/ajax/libs/ethers/6.7.0/ethers.min.js";
@@ -377,7 +103,7 @@
async function fetchSigil(ship) {
try {
- const response = await fetch('/zodiac/sigil/' + ship);
+ const response = await fetch(sigilUrl + ship);
if (response.ok) {
const data = await response.text();
return data;
@@ -390,7 +116,7 @@
}
async function fetchSecret() {
try {
- const response = await fetch('/zodiac/metamask');
+ const response = await fetch(secretUrl);
if (response.ok) {
const data = await response.json();
return data.challenge;
@@ -428,21 +154,20 @@
async function metamaskLogin(account, point){
// Fetch the secret from the server
- const secret = await fetchSecret();
- console.log({secret});
+ const challenge = await fetchSecret();
const signature = await window.ethereum.request({
method: "personal_sign",
- params: [secret, account],
+ params: [challenge, account],
});
- const response = await fetch('/zodiac/auth', {
+ const response = await fetch(authUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
who: Number(point),
- secret: secret,
+ challenge,
address: account,
signature: signature
}),
@@ -450,7 +175,7 @@
if (response.ok) {
// location.reload();
- window.location.replace('/zodiac');
+ window.location.replace(redirectUrl);
} else {
alert("Login failed. Please try again.");
}
diff --git a/web/router.hoon b/web/router.hoon
index f5fc388..c554e41 100644
--- a/web/router.hoon
+++ b/web/router.hoon
@@ -1,22 +1,14 @@
-/- sur=zodiac
-/+ server, metamask, sr=sortug
+/- sur=neyre, coki
+/+ server, metamask, sr=sortug, cokil=coki
/= login-page /web/login
/= index-page /web/index
/= sigil-html /web/sigil/sigil
-|_ [=bowl:gall eyre-id=@ta req=inbound-request:eyre state=versioned-state:sur]
-+* metalib ~(. metamask [sessions.state bowl])
-++ session-timeout ~d300
-++ session-cookie-string
- |= [session=@uv extend=?]
- ^- @t
- %- crip
- =; max-age=tape
- :: "urbauth-{(scow %p src.bowl)}={(scow %uv session)}; Path=/; Max-Age={max-age}"
- "ucm-{(scow %p src.bowl)}={(scow %uv session)}; Path=/; Max-Age={max-age}"
- %+ scow:parsing:sr %ud
- ?. extend 0
- (div (msec:milly session-timeout) 1.000)
+=+ base-path=`path`/coki
+|_ [=bowl:gall eyre-id=@ta req=inbound-request:eyre state=versioned-state:sur =sessions:coki]
+
++* cokilib ~(. cokil [sessions bowl])
+ metalib ~(. metamask [sessions bowl])
++ get-file-at
|= [base=path file=path ext=@ta]
@@ -32,30 +24,14 @@
%- as-octs:mimes:html
.^(@ %cx path)
-++ handle-get-request
- |= [headers=header-list:http request-line:server]
- ^- simple-payload:http
- ?~ ext $(ext `%html, site [%index ~])
- ?: ?=([%zodiac *] site) $(site +.site)
- :: serve dynamic session.js
- ::
- ?: =([/session `%js] [site ext])
- %- js-response:gen:server
- %- as-octt:mimes:html
- """
- window.ship = '{(scow %p src.bowl)}';
- """
- =/ file=(unit octs)
- (get-file-at /web site u.ext)
- ?~ file ~& "file not found" not-found:gen:server
- ?+ u.ext not-found:gen:server
- %html (html-response:gen:server u.file)
- %js (js-response:gen:server u.file)
- %css (css-response:gen:server u.file)
- %png (png-response:gen:server u.file)
- %woff (woff-response:gen:server u.file)
- %woff2 (woff2-response:gen:server u.file)
- ==
+
+ ++ serve-json |= jon=json
+ (send-response (json-response:gen:server jon))
+++ serve-error |= [status=@ud msg=@t]
+ =/ octs (as-octs:mimes:html msg)
+ =/ headers=header-list:http [['content-type' 'text/plain'] ~]
+ =/ sp=simple-payload:http [[status headers] `octs]
+ (send-response sp)
++ ebail
@@ -78,17 +54,14 @@
++ send-response
|= =simple-payload:http
- =/ cookie ['set-cookie' (session-cookie-string 0vublog .y)]
- =. headers.response-header.simple-payload
- [cookie headers.response-header.simple-payload]
%+ give-simple-payload:app:server eyre-id simple-payload
++ validate-coki
=/ coki (get-header:http 'cookie' header-list.request.req)
?~ coki ~
- (validate-coki:metalib u.coki)
+ (validate-coki:cokilib u.coki)
-++ login-ajax
+++ login-ajax |= base-slug=@tas
=/ referer (get-header:http 'referer' header-list.request.req)
~& referer=referer
?~ referer .n
@@ -96,33 +69,88 @@
?~ parsed .n
=/ =path q.q.u.parsed
~& login-ajax=path
- ?= [%zodiac %login ~] path
-++ route
+ ?~ path .n
+ =/ hd i.path =/ tl t.path
+ ~& >> [slug=base-slug hd tl]
+ =/ same-base .=(i.path base-slug)
+ ?& same-base ?=([%login ~] tl) ==
+
+++ route ^- (list card:agent:gall)
+ =. base-path ?: ?=([%coki ~] base-path) /[dap.bowl] base-path
+ =/ bpath (spat base-path)
+
+ =/ base-slug =/ bp `(list @t)`base-path ?~ bp dap.bowl i.bp
+ =/ subpaths /[base-slug]
=/ rl (parse-request-line:server url.request.req)
- =/ sitepath=path /[(head site.rl)]
+ =. site.rl ?~ site.rl site.rl ?: .=(base-slug i.site.rl) t.site.rl site.rl
=/ pat=(pole knot) site.rl
- ?: ?=([%zodiac %login ~] pat) serve-login-page
- ?: login-ajax (serve-unauthed pat)
+ ~& > pat=pat
+ ~& [url.request.req base-path base-slug bpath pat subpaths src.bowl]
+
+ |^
+ ?: ?=([%login ~] pat) serve-login-page
+ ?: (login-ajax base-slug) serve-unauthed
=/ muser validate-coki
- ?~ muser redirect-to-login
+ ~& >>> muser=muser
+ ?~ muser (redirect (weld subpaths /login))
=. src.bowl u.muser
+ serve-authed
+
+ ++ serve-authed
?+ pat ebail
- [%zodiac %logout *] (logout:metalib eyre-id (need (get-header:http 'cookie' header-list.request.req)))
- [%zodiac ~] serve-root
+ [%logout *] (logout:cokilib eyre-id (need (get-header:http 'cookie' header-list.request.req)) bpath)
+ :: [~] serve-root
+ ~ serve-root
:: [site=@t *] (send-response (handle-get-request header-list.request.req rl))
+ ::
+ [%poke *] ~& >> bowl=bowl (redirect base-path)
+ ==
+ ++ serve-unauthed
+ ?+ pat ebail
+ [%sigil point=@ ~] (serve-sigil point.pat)
+ [%metamask *] (serve-metamask-challenge:metalib eyre-id)
+ [%auth *]
+ =/ res (process-metamask-auth:metalib eyre-id body.request.req bpath base-slug)
+ ?- -.res %& +.res %| (serve-error +.res) ==
+
==
-++ serve-unauthed |= pat=(pole knot)
-?+ pat ebail
- [%zodiac %metamask rest=*] (serve-metamask-challenge:metalib eyre-id)
- [%zodiac %auth rest=*] (process-metamask-auth:metalib eyre-id body.request.req)
- [%zodiac %sigil point=@ ~] (serve-sigil point.pat)
-==
-++ redirect-to-login
- (send-response (redirect:gen:server '/zodiac/login'))
-++ serve-root
- (send-response (manx-payload (index-page bowl)))
+ ++ redirect |= =path
+ (send-response (redirect:gen:server (spat path)))
+ ++ serve-root
+ (send-response (manx-payload (index-page bowl (trip base-slug))))
+
+ ++ serve-login-page
+ (send-response (manx-payload (login-page bowl (trip base-slug) (trip (spat base-path)))))
+
+ ++ handle-get-request
+ |= [headers=header-list:http request-line:server]
+ ^- simple-payload:http
+ ?~ ext $(ext `%html, site [%index ~])
+ =/ pat `(pole knot)`site
+ ?: ?&(?=([slug=@t *] pat) .=(slug.pat base-slug)) $(site +.site)
+ :: serve dynamic session.js
+ ::
+ ?: =([/session `%js] [site ext])
+ %- js-response:gen:server
+ %- as-octt:mimes:html
+ """
+ window.ship = '{(scow %p src.bowl)}';
+ """
+ =/ file=(unit octs)
+ (get-file-at /web site u.ext)
+ ?~ file ~& "file not found" not-found:gen:server
+ ?+ u.ext not-found:gen:server
+ %html (html-response:gen:server u.file)
+ %js (js-response:gen:server u.file)
+ %css (css-response:gen:server u.file)
+ %png (png-response:gen:server u.file)
+ %woff (woff-response:gen:server u.file)
+ %woff2 (woff2-response:gen:server u.file)
+ ==
+
+
+ --
::
-++ serve-login-page (send-response (manx-payload (login-page bowl)))
++ serve-sigil |= param=@t
=/ sip (slaw:parsing:sr %ud param)
?~ sip ebail
@@ -130,9 +158,8 @@
(send-response (manx-payload sigil-div))
-++ eyre-binding-card
-|= =path
- ~& > adding-binding=[path dap.bowl]
+++ eyre-binding-card |= =path
+ ~& >> adding-binding=[path dap.bowl]
[%pass /eyre/connect %arvo %e %connect [~ path] dap.bowl]
--