wrap async calls into promises

safari complains about bare async calls not being triggered by user action after a click
allow admins to have multiple open sessions
general webapp tweaks to background colors and button widths
This commit is contained in:
Roberto Hidalgo 2023-10-01 23:21:28 -06:00
parent 81fbcba5a0
commit a8d18d8812
9 changed files with 72 additions and 23 deletions

View File

@ -55,10 +55,10 @@ func LoginHandler(w http.ResponseWriter, req *http.Request, ps httprouter.Params
if err := user.Login(password); err != nil { if err := user.Login(password); err != nil {
code := http.StatusBadRequest code := http.StatusBadRequest
status := http.StatusText(code) status := http.StatusText(code)
if err, ok := err.(*errors.InvalidCredentials); ok { if invalidCreds, ok := err.(*errors.InvalidCredentials); ok {
code = err.Code() code = invalidCreds.Code()
status = err.Error() status = invalidCreds.Error()
err.Log() invalidCreds.Log()
} else { } else {
logrus.Errorf("could not login %s: %s", username, err.Error()) logrus.Errorf("could not login %s: %s", username, err.Error())
} }

View File

@ -71,8 +71,10 @@ func NewSession(user *user.User, table db.Collection) (*Session, error) {
Expires: user.TTL.FromNow(), Expires: user.TTL.FromNow(),
} }
if !user.IsAdmin {
// delete previous sessions // delete previous sessions
table.Find(db.Cond{"user": user.ID}).Delete() table.Find(db.Cond{"user": user.ID}).Delete()
}
// insert new one // insert new one
_, err := table.Insert(sess) _, err := table.Insert(sess)
return sess, err return sess, err

View File

@ -4,7 +4,7 @@
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
<title>puerta@nidi.to</title> <title>puerta@nidi.to</title>
<link rel="stylesheet" href="https://cdn.rob.mx/css/fonts.css" /> <link rel="stylesheet" href="https://cdn.rob.mx/css/fonts.css" />
<link rel="stylesheet" href="https://cdn.rob.mx/nidito/index.css" /> <link rel="stylesheet" href="https://cdn.rob.mx/nidito/index.css" />
@ -16,6 +16,7 @@
<link rel="apple-touch-icon" sizes="152x152" href="/static/icon/152.png"> <link rel="apple-touch-icon" sizes="152x152" href="/static/icon/152.png">
<link rel="apple-touch-icon" sizes="384x384" href="/static/icon/384.png"> <link rel="apple-touch-icon" sizes="384x384" href="/static/icon/384.png">
<link rel="apple-touch-icon" sizes="192x192" href="/static/icon/192.png"> <link rel="apple-touch-icon" sizes="192x192" href="/static/icon/192.png">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
<style> <style>
#user-list { #user-list {
display: grid; display: grid;
@ -250,7 +251,7 @@
</section> </section>
</main> </main>
<script type="module" src="https://unpkg.com/@github/webauthn-json@2.0.2/dist/esm/webauthn-json.browser-ponyfill.js"></script> <script type="module" src="https://unpkg.com/@github/webauthn-json@2.1.1/dist/esm/webauthn-json.browser-ponyfill.js"></script>
<script>window._PushKey = "$PUSH_KEY$"</script> <script>window._PushKey = "$PUSH_KEY$"</script>
<script type="module" src="/static/admin.js"></script> <script type="module" src="/static/admin.js"></script>
</body> </body>

View File

@ -4,7 +4,8 @@
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
<title>puerta@nidi.to</title> <title>puerta@nidi.to</title>
<link rel="stylesheet" href="https://cdn.rob.mx/css/fonts.css" /> <link rel="stylesheet" href="https://cdn.rob.mx/css/fonts.css" />
<link rel="stylesheet" href="https://cdn.rob.mx/nidito/index.css" /> <link rel="stylesheet" href="https://cdn.rob.mx/nidito/index.css" />
@ -16,6 +17,7 @@
<link rel="apple-touch-icon" sizes="152x152" href="/static/icon/152.png"> <link rel="apple-touch-icon" sizes="152x152" href="/static/icon/152.png">
<link rel="apple-touch-icon" sizes="384x384" href="/static/icon/384.png"> <link rel="apple-touch-icon" sizes="384x384" href="/static/icon/384.png">
<link rel="apple-touch-icon" sizes="192x192" href="/static/icon/192.png"> <link rel="apple-touch-icon" sizes="192x192" href="/static/icon/192.png">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
</head> </head>
<body> <body>
<header id="main-header"> <header id="main-header">
@ -29,7 +31,7 @@
<button id="rex">Abrir</button> <button id="rex">Abrir</button>
</form> </form>
</main> </main>
<script type="module" src="https://unpkg.com/@github/webauthn-json@2.0.2/dist/esm/webauthn-json.browser-ponyfill.js"></script> <script type="module" src="https://unpkg.com/@github/webauthn-json@2.1.1/dist/esm/webauthn-json.browser-ponyfill.js"></script>
<script type="module" src="/static/index.js" async="async"></script> <script type="module" src="/static/index.js" async="async"></script>
</body> </body>
</html> </html>

View File

@ -4,11 +4,12 @@
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
<title>puerta@nidi.to</title> <title>puerta@nidi.to</title>
<link rel="stylesheet" href="https://cdn.rob.mx/css/fonts.css" /> <link rel="stylesheet" href="https://cdn.rob.mx/css/fonts.css" />
<link rel="stylesheet" href="https://cdn.rob.mx/nidito/index.css" /> <link rel="stylesheet" href="https://cdn.rob.mx/nidito/index.css" />
<link rel="stylesheet" href="/static/index.css" /> <link rel="stylesheet" href="/static/index.css" />
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
<!--link rel="manifest" href="/static/manifest.webmanifest" /--> <!--link rel="manifest" href="/static/manifest.webmanifest" /-->
</head> </head>
<body> <body>

View File

@ -12,6 +12,7 @@ import (
"mime" "mime"
"net/http" "net/http"
"os" "os"
"strings"
"time" "time"
"git.rob.mx/nidito/puerta/internal/auth" "git.rob.mx/nidito/puerta/internal/auth"
@ -223,7 +224,7 @@ func Initialize(config *Config) (http.Handler, error) {
wan, err := webauthn.New(&webauthn.Config{ wan, err := webauthn.New(&webauthn.Config{
RPDisplayName: config.Name, RPDisplayName: config.Name,
RPID: config.HTTP.Origin, RPID: strings.Split(config.HTTP.Origin, ":")[0],
RPOrigins: origins, RPOrigins: origins,
}) })
if err != nil { if err != nil {

View File

@ -299,6 +299,7 @@ window.addEventListener("load", async function() {
type: "module", type: "module",
scope: "/" scope: "/"
}) })
console.info(`Registered service worker`, reg)
} catch(err) { } catch(err) {
console.log(`Could not register serviceworker: ${err}`) console.log(`Could not register serviceworker: ${err}`)
pnb.style.display = "none" pnb.style.display = "none"
@ -317,6 +318,7 @@ window.addEventListener("load", async function() {
} }
} catch(err) { } catch(err) {
console.error("Could not get pushmanager subscription", err) console.error("Could not get pushmanager subscription", err)
pnb.style.display = "none"
} }
@ -328,14 +330,6 @@ window.addEventListener("load", async function() {
console.error("Could not get pushmanager subscription", err) console.error("Could not get pushmanager subscription", err)
} }
if (sub) {
pnb.classList.add("subscribed")
pnb.innerHTML = "🔕"
} else {
pnb.classList.remove("subscribed")
pnb.innerHTML = "🔔"
}
if (!pnb.classList.contains("subscribed")) { if (!pnb.classList.contains("subscribed")) {
if (await createPushSubscription()) { if (await createPushSubscription()) {
pnb.classList.add("subscribed") pnb.classList.add("subscribed")
@ -347,6 +341,14 @@ window.addEventListener("load", async function() {
pnb.innerHTML = "🔔" pnb.innerHTML = "🔔"
} }
} }
if (sub) {
pnb.classList.add("subscribed")
pnb.innerHTML = "🔕"
} else {
pnb.classList.remove("subscribed")
pnb.innerHTML = "🔔"
}
}) })
}) })

View File

@ -1,16 +1,25 @@
/* SPDX-License-Identifier: Apache-2.0 /* SPDX-License-Identifier: Apache-2.0
Copyright © 2022 Roberto Hidalgo <nidito@un.rob.mx> */ Copyright © 2022 Roberto Hidalgo <nidito@un.rob.mx> */
button { button {
background: rgba(255,255,255,.6); background: rgba(255,255,255,.6);
font-family: "Aestetico", sans-serif; font-family: "Aestetico", sans-serif;
font-weight: bold; font-weight: bold;
text-align: center; text-align: center;
display: block;
color: #c11145; color: #c11145;
border: 5px solid #c11145; border: 5px solid #c11145;
transition: all ease-in-out .5s; transition: all ease-in-out .5s;
} }
main.container button {
display: block;
box-sizing: border-box;
width: 100%;
font-size: 1.5em;
border-radius: .4em;
font-weight: bold;
}
.container { .container {
box-sizing: border-box; box-sizing: border-box;
} }
@ -85,11 +94,38 @@ input[type=checkbox] {
} }
@media screen and (max-width: 768px) { @media screen and (max-width: 768px) {
html { height: -webkit-fill-available; }
body {
background-color: #c11145;
display: flex;
flex-direction: column;
min-height: 100vh;
min-height: -webkit-fill-available;
}
main {
background-color: rgb(255, 198, 215);
flex-grow: 1;
}
#main-header {
position: sticky;
padding-top: env(safe-area-inset-top);
top: 0;
}
input { input {
max-width: 100%; max-width: 100%;
} }
button { button {
max-width: 100%; max-width: 100%;
} }
#auth {
max-width: 100%;
}
.container {
padding-bottom: env(safe-area-inset-bottom);
}
} }

View File

@ -38,7 +38,9 @@ export async function withAuth(target, config) {
if (step == "register") { if (step == "register") {
// server told us to register new credentials // server told us to register new credentials
// we try to do that // we try to do that
await register(challenge, target) await new Promise((res,rej) => {
register(challenge, target).then(res).catch(rej)
})
// and retry the original request if successful // and retry the original request if successful
return await new Promise((res, rej) => { return await new Promise((res, rej) => {
setTimeout(async () => { setTimeout(async () => {
@ -51,7 +53,9 @@ export async function withAuth(target, config) {
}) })
} else if (step == "login") { } else if (step == "login") {
// server told us to use existing credential for request // server told us to use existing credential for request
return await login(challenge, target, config) return await new Promise((res,rej) => {
return login(challenge, target, config).then(res).catch(rej)
})
} }
throw `Unknown webauthn step: <${step}>` throw `Unknown webauthn step: <${step}>`