summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpolwex <polwex@sortug.com>2025-06-22 23:11:11 +0700
committerpolwex <polwex@sortug.com>2025-06-22 23:11:11 +0700
commit6fb80b2d94a5282c8350278e299bfcb2d0b60d40 (patch)
treebe85636f67322948181bf59519dfe998f7d7b6b1
parent4e2a84761b95a29c02c77c575810ab49f2af7335 (diff)
-rw-r--r--app/neyre.hoon (renamed from app/zodiac.hoon)37
-rw-r--r--desk.bill2
-rw-r--r--lib/coki.hoon92
-rw-r--r--lib/metamask.hoon147
-rw-r--r--sur/coki.hoon21
-rw-r--r--sur/neyre.hoon (renamed from sur/zodiac.hoon)2
-rw-r--r--web/index.hoon8
-rw-r--r--web/login.hoon311
-rw-r--r--web/router.hoon159
9 files changed, 272 insertions, 507 deletions
diff --git a/app/zodiac.hoon b/app/neyre.hoon
index 0718da1..e8f2c17 100644
--- a/app/zodiac.hoon
+++ b/app/neyre.hoon
@@ -1,18 +1,23 @@
-/- *zodiac
-/+ dbug, metamask
+/- *neyre, coki
+/+ dbug, cokil=coki
/= router /web/router
+=| sessions:coki
+=* sessions -
=| versioned-state
=* state -
%- agent:dbug
^- agent:gall
|_ =bowl:gall
+* this .
- metalib ~(. metamask [sessions.state bowl])
+ cokilib ~(. cokil [sessions bowl])
++ on-init
^- (quip card:agent:gall agent:gall)
:_ this
=/ weblib router(bowl bowl)
- :~((eyre-binding-card:weblib /zodiac))
+ =/ weblib2 weblib(base-path /)
+ :~ (eyre-binding-card:weblib2 /)
+ (eyre-binding-card:weblib2 /[dap.bowl])
+ ==
::
++ on-save
^- vase
@@ -32,27 +37,17 @@
++ on-poke
|= [=mark =vase]
^- (quip card:agent:gall agent:gall)
- |^
?+ mark `this
- %noun (on-poke-noun !<(* vase))
+ %coki =^ cards sessions (handle-self-poke:cokilib !<(self-poke:coki vase))
+ [cards this]
%handle-http-request
+ ~& "handling http"
=/ order !<([id=@ta req=inbound-request:eyre] vase)
- =/ weblib ~(. router [bowl id.order req.order state])
- :- route:weblib this
+ =/ weblib ~(. router [bowl id.order req.order state sessions])
+ =/ weblib2 weblib(base-path /)
+ :- route:weblib2 this
+ %noun ~& > s=sessions `this
==
- ++ on-poke-noun |= a=*
- ?: ?= [%logout @ @] a
- ~& "loggingout"
- =^ cards sessions.state (handle-logout:metalib +.a)
- [cards this]
-
- =. sessions.state
- ?+ a sessions.state
- [%meta @t] (handle-meta:metalib +.a)
- [%auth @p @ @uv] (handle-auth:metalib +.a)
- ==
- `this
- --
::
++ on-watch
|~ path
diff --git a/desk.bill b/desk.bill
index 32ce7b6..60b282a 100644
--- a/desk.bill
+++ b/desk.bill
@@ -1,2 +1,2 @@
-:~ %zodiac
+:~ %neyre
==
diff --git a/lib/coki.hoon b/lib/coki.hoon
new file mode 100644
index 0000000..39ea479
--- /dev/null
+++ b/lib/coki.hoon
@@ -0,0 +1,92 @@
+/- *coki
+/+ server, sr=sortug
+|_ [=sessions =bowl:gall]
++$ sess ^sessions
+++ session-timeout
+ |%
+ ++ host ~d30
+ ++ guest ~d7
+ --
+++ session-hash
+ (~(raw og (shas %coki eny.bowl)) 128)
+++ session-cookie-string |= [session=@ proven=@p desk=@tas]
+ ^- @t
+ =/ max-age=tape %- a-co:co
+ =/ its-a-me .=(src.bowl our.bowl)
+ =, session-timeout
+ (div (msec:milly ?:(its-a-me host guest)) 1.000)
+ %- crip
+ "urbcoki-{(trip desk)}-{(scow %p proven)}={(scow:parsing:sr %uv session)}; Path=/{(trip desk)}; HttpOnly; SameSite=Lax; Max-Age={max-age}"
+ :: "urbneo={(scow:parsing:sr %uv session)}; Path=/; Max-Age={max-age}"
+++ validate-coki |= coki=@t ^- (unit @p)
+ =/ cookies (rush coki cock:de-purl:html)
+ ~& cookies=cookies
+ ?~ cookies ~
+ =/ cokis=(list [@t @t]) u.cookies
+ |-
+ ?~ cokis ~
+ =/ hd i.cokis
+ :: ?: (contains:string:sr (trip hd) "urbneo")
+ =/ hash (slaw:parsing:sr %uv +.hd)
+ ?~ hash $(cokis t.cokis)
+ =/ sess (~(get by users.sessions) u.hash)
+ ?~ sess $(cokis t.cokis)
+ `u.sess
+++ send-self-poke |= poke=self-poke
+ ^- (list card:agent:gall)
+ :~ [%pass /gib %agent [our.bowl dap.bowl] %poke %coki !>(poke)]
+ ==
+:: handle-self-pokes
+++ handle-self-poke |= poke=self-poke
+?- -.poke
+ %meta :- ~ (handle-challenge +.poke)
+ %coki :- ~ (handle-coki +.poke)
+ %logout (handle-logout +.poke)
+==
+++ handle-challenge
+ |= new-challenge=@ ^- ^sessions
+ :: =? users.sessions
+ :: !(~(has by users.sessions) src.bowl)
+ :: (~(put by users.sessions) [src.bowl src.bowl])
+ :: =? challenges.sessions
+ :: =(src.bowl (~(got by users.sessions) src.bowl))
+ =. challenges.sessions
+ (~(put in challenges.sessions) new-challenge)
+
+ sessions
+
+
+++ parse-coki |= coki=@t
+ =/ cookies (rush coki cock:de-purl:html)
+ ?~ cookies users.sessions
+ =/ cokis=(list [@t @t]) u.cookies
+ |-
+ ?~ cokis users.sessions
+ =/ hd i.cokis
+ :: ?: (contains:string:sr (trip hd) "urbneo")
+ =/ hash (slaw:parsing:sr %uv +.hd)
+ ?~ hash $(cokis t.cokis)
+ =/ sess (~(get by users.sessions) u.hash)
+ ?~ sess $(cokis t.cokis)
+ (~(del by users.sessions) u.hash)
+
+++ logout |= [order-id=@t coki=@t redirect=@t]
+ (send-self-poke [%logout order-id coki redirect])
+
+++ handle-logout |= [order-id=@t coki=@t redirect=@t]
+ ~& handling-logout=coki
+ =/ new-users (parse-coki coki)
+ :_ sessions(users new-users)
+ %+ give-simple-payload:app:server
+ order-id
+ (redirect:gen:server redirect)
+
+ ++ handle-coki
+ |= [who=@p coki=@ =challenge] ^- ^sessions
+ :: ~& > "%ustj: Successful authentication of {<src>} as {<who>}."
+ =. users.sessions (~(put by users.sessions) coki who)
+ =. challenges.sessions (~(del in challenges.sessions) challenge)
+ sessions
+
+
+--
diff --git a/lib/metamask.hoon b/lib/metamask.hoon
index 3456692..09e2f66 100644
--- a/lib/metamask.hoon
+++ b/lib/metamask.hoon
@@ -1,70 +1,53 @@
-/+ naive, ethereum, server, sr=sortug
-=>
-|%
-+$ challenges (set secret)
-+$ secret @uv
-+$ authorization
- $: who=@p
- =secret
- adr=tape
- sig=tape
- ==
-:: +$ user-sessions (map coki=@ [proven=@p src=@p])
-+$ user-sessions (map coki=@ ship=@p)
-+$ sessions
- $: =challenges
- users=user-sessions
- ==
---
-|_ [=sessions =bowl:gall]
-+$ sess ^sessions
-:: state field to keep track of users logged with metamask
- :: this goes on the router
+/- coki
+/+ naive, ethereum, sr=sortug, cokil=coki, server
+|_ [=sessions:coki =bowl:gall]
++* cokilib ~(. cokil [sessions bowl])
+
++ serve-metamask-challenge
|= eyre-id=@ta
:: special-case MetaMask auth handling
=/ new-challenge (sham [now eny]:bowl)
- %+ weld (self-poke [%meta new-challenge])
+ =/ jon (enjs-challenge new-challenge)
+ %+ weld (send-self-poke:cokilib [%meta new-challenge])
%+ give-simple-payload:app:server
eyre-id
- ^- simple-payload:http
- :- :- 200
- ~[['Content-Type' 'application/json']]
- `(as-octs:mimes:html (en:json:html (enjs-challenge new-challenge)))
+ (json-response:gen:server jon)
+ ::
:: Modified from ~rabsef-bicrym's %mask by ~hanfel-dovned.
++ process-metamask-auth
- |= [order-id=@t octs=(unit octs)]
- ^- (list card:agent:gall)
+ |= [order-id=@t octs=(unit octs) redirect-path=@t base-slug=@t]
+ ^- (each (list card:agent:gall) [@ud @t])
=/ challenges challenges.sessions
|^
- ?~ octs ~|(%empty-auth-request !!)
+ ?~ octs [%.n 403 %empty-auth-request]
:: ?. =('auth' (cut 3 [0 4] q.u.octs))
:: *(list card:agent:gall)
=/ jon (de:json:html q.u.octs)
- ?~ jon ~|(%empty-auth-json !!)
+ ?~ jon [%.n 403 %empty-auth-json]
=/ body=json u.jon
=/ axn (dejs-action body)
- =/ is-valid (validate who.axn secret.axn adr.axn sig.axn)
- ~& >> signature-valid=[is-valid who.axn secret.axn adr.axn sig.axn]
- ?. is-valid ~|(%bad-metamask-signature !!)
+ =/ is-valid (validate who.axn challenge.axn adr.axn sig.axn)
+ ~& >> signature-valid=[is-valid who.axn challenge.axn adr.axn sig.axn]
+ ?. is-valid [%.n 403 %bad-metamask-signature]
- =/ coki-hash session-hash
- =/ coki (session-cookie-string coki-hash who.axn)
+ =/ coki-hash session-hash:cokilib
+ =/ coki (session-cookie-string:cokilib coki-hash who.axn base-slug)
+ :- %.y
%+ weld
- (self-poke [%auth who.axn coki-hash secret.axn])
+ (send-self-poke:cokilib [%coki who.axn coki-hash challenge.axn])
%+ give-simple-payload:app:server
order-id
^- simple-payload:http
:- :- 303
:~
['set-cookie' coki]
- ['location' '/zodiac']
+ ['location' redirect-path]
==
=/ obj=json %- pairs:enjs:format :~([%login-ok [%b .y]])
`(as-octs:mimes:html (en:json:html obj))
++ validate
- |= [who=@p challenge=secret address=tape hancock=tape]
+ |= [who=@p =challenge:coki address=tape hancock=tape]
^- ?
=/ addy (from-tape address)
=/ cock (from-tape hancock)
@@ -127,13 +110,13 @@
==
++ dejs-action
|= jon=json
- ^- authorization
+ ^- authorization:cokilib
=, dejs:format
%. jon
%- ot
:: :~ [%who (se %p)]
:~ [%who ni]
- [%secret (se %uv)]
+ [%challenge (se %uv)]
[%address sa]
[%signature sa]
==
@@ -145,87 +128,5 @@
%- pairs
:~ [%challenge [%s (scot %uv chal)]]
==
- ++ self-poke
- |= noun=*
- ^- (list card:agent:gall)
- :~ [%pass /gib %agent [our.bowl dap.bowl] %poke %noun !>(noun)]
- ==
-
- :: these are the poke handlers
- ++ handle-meta
- |= new-challenge=@ ^- ^sessions
- :: =? users.sessions
- :: !(~(has by users.sessions) src.bowl)
- :: (~(put by users.sessions) [src.bowl src.bowl])
- :: =? challenges.sessions
- :: =(src.bowl (~(got by users.sessions) src.bowl))
- =. challenges.sessions
- (~(put in challenges.sessions) new-challenge)
- sessions
- ++ handle-auth
- |= [who=@p coki=@ =secret] ^- ^sessions
- :: ~& > "%ustj: Successful authentication of {<src>} as {<who>}."
- =. users.sessions (~(put by users.sessions) coki who)
- =. challenges.sessions (~(del in challenges.sessions) secret)
- sessions
-
- ++ session-timeout
- |%
- ++ auth ~d30
- ++ guest ~d7
- --
- ++ session-hash
- (~(raw og (shas %coki eny.bowl)) 128)
- ++ session-cookie-string |= [session=@ proven=@p]
- ^- @t
- =/ max-age=tape %- a-co:co
- =/ its-a-me .=(src.bowl our.bowl)
- =, session-timeout
- (div (msec:milly ?:(its-a-me auth guest)) 1.000)
- %- crip
- "urbneo-{(scow %p proven)}={(scow:parsing:sr %uv session)}; Path=/; Max-Age={max-age}"
- :: "urbneo={(scow:parsing:sr %uv session)}; Path=/; Max-Age={max-age}"
- ++ validate-coki |= coki=@t ^- (unit @p)
- ~& >> validating-coki=coki
- =/ cookies (rush coki cock:de-purl:html)
- ~& cookies=cookies
- ?~ cookies ~
- =/ cokis=(list [@t @t]) u.cookies
- |-
- ?~ cokis ~
- =/ hd i.cokis
- :: ?: (contains:string:sr (trip hd) "urbneo")
- ~& key=-.hd
- =/ hash (slaw:parsing:sr %uv +.hd)
- ?~ hash $(cokis t.cokis)
- ~& hash=`@uv`u.hash
- =/ sess (~(get by users.sessions) u.hash)
- ~& sess=sess
- ?~ sess $(cokis t.cokis)
- `u.sess
- ++ parse-coki |= coki=@t
- =/ cookies (rush coki cock:de-purl:html)
- ?~ cookies users.sessions
- =/ cokis=(list [@t @t]) u.cookies
- |-
- ?~ cokis users.sessions
- =/ hd i.cokis
- :: ?: (contains:string:sr (trip hd) "urbneo")
- ~& key=-.hd
- =/ hash (slaw:parsing:sr %uv +.hd)
- ?~ hash $(cokis t.cokis)
- =/ sess (~(get by users.sessions) u.hash)
- ?~ sess $(cokis t.cokis)
- (~(del by users.sessions) u.hash)
-
- ++ logout |= [order-id=@t coki=@t]
- (self-poke [%logout order-id coki])
- ++ handle-logout |= [order-id=@t coki=@t]
- ~& handling-logout=coki
- =/ new-users (parse-coki coki)
- :_ sessions(users new-users)
- %+ give-simple-payload:app:server
- order-id
- (redirect:gen:server '/zodiac/login')
--
diff --git a/sur/coki.hoon b/sur/coki.hoon
new file mode 100644
index 0000000..37adcd0
--- /dev/null
+++ b/sur/coki.hoon
@@ -0,0 +1,21 @@
+|%
++$ challenges (set challenge)
++$ challenge @uv
++$ authorization
+ $: who=@p
+ challenge=@uv
+ adr=tape
+ sig=tape
+ ==
+:: +$ user-sessions (map coki=@ [proven=@p src=@p])
++$ user-sessions (map coki=@ ship=@p)
++$ sessions
+ $: =challenges
+ users=user-sessions
+ ==
++$ self-poke
+ $% [%meta challenge=@uv]
+ [%coki who=@p coki=@ challenge=@uv]
+ [%logout eyre-id=@t coki=@t redirect=@t]
+ ==
+--
diff --git a/sur/zodiac.hoon b/sur/neyre.hoon
index 3d20610..f004def 100644
--- a/sur/zodiac.hoon
+++ b/sur/neyre.hoon
@@ -5,6 +5,6 @@
==
+$ state-0
$: %0
- sessions=sess:metalib
+ placeholder=@
==
--
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]
--