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 {
code := http.StatusBadRequest
status := http.StatusText(code)
if err, ok := err.(*errors.InvalidCredentials); ok {
code = err.Code()
status = err.Error()
err.Log()
if invalidCreds, ok := err.(*errors.InvalidCredentials); ok {
code = invalidCreds.Code()
status = invalidCreds.Error()
invalidCreds.Log()
} else {
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(),
}
if !user.IsAdmin {
// delete previous sessions
table.Find(db.Cond{"user": user.ID}).Delete()
}
// insert new one
_, err := table.Insert(sess)
return sess, err

View File

@ -4,7 +4,7 @@
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta charset="utf-8" />
<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>
<link rel="stylesheet" href="https://cdn.rob.mx/css/fonts.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="384x384" href="/static/icon/384.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>
#user-list {
display: grid;
@ -250,7 +251,7 @@
</section>
</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 type="module" src="/static/admin.js"></script>
</body>

View File

@ -4,7 +4,8 @@
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta charset="utf-8" />
<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>
<link rel="stylesheet" href="https://cdn.rob.mx/css/fonts.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="384x384" href="/static/icon/384.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>
<body>
<header id="main-header">
@ -29,7 +31,7 @@
<button id="rex">Abrir</button>
</form>
</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>
</body>
</html>

View File

@ -4,11 +4,12 @@
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta charset="utf-8" />
<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>
<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="/static/index.css" />
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
<!--link rel="manifest" href="/static/manifest.webmanifest" /-->
</head>
<body>

View File

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

View File

@ -299,6 +299,7 @@ window.addEventListener("load", async function() {
type: "module",
scope: "/"
})
console.info(`Registered service worker`, reg)
} catch(err) {
console.log(`Could not register serviceworker: ${err}`)
pnb.style.display = "none"
@ -317,6 +318,7 @@ window.addEventListener("load", async function() {
}
} catch(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)
}
if (sub) {
pnb.classList.add("subscribed")
pnb.innerHTML = "🔕"
} else {
pnb.classList.remove("subscribed")
pnb.innerHTML = "🔔"
}
if (!pnb.classList.contains("subscribed")) {
if (await createPushSubscription()) {
pnb.classList.add("subscribed")
@ -347,6 +341,14 @@ window.addEventListener("load", async function() {
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
Copyright © 2022 Roberto Hidalgo <nidito@un.rob.mx> */
button {
background: rgba(255,255,255,.6);
font-family: "Aestetico", sans-serif;
font-weight: bold;
text-align: center;
display: block;
color: #c11145;
border: 5px solid #c11145;
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 {
box-sizing: border-box;
}
@ -85,11 +94,38 @@ input[type=checkbox] {
}
@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 {
max-width: 100%;
}
button {
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") {
// server told us to register new credentials
// 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
return await new Promise((res, rej) => {
setTimeout(async () => {
@ -51,7 +53,9 @@ export async function withAuth(target, config) {
})
} else if (step == "login") {
// 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}>`