lol, 64bit integer overflows are fun to debug
specially when running a multi-arch cluster and HA with poor observability. a `time.Duration` was being casted to an `int` (because I clearly have no clue of what I'm doing). All is well on 64-bit processors, but 32-bit processors choke on the very long micro-second precision int, overflow, and turn `7d`, around `604800` seconds into `-114753536` seconds, which the browser happily (and correctly) turns into a cookie sent to /dev/null. lol.
This commit is contained in:
parent
e57ebc7108
commit
038e09b202
|
@ -130,30 +130,30 @@
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
<form action="/api/user/:id" class="user-info-panel-details hidden">
|
<form action="/api/user/:id" class="user-info-panel-details hidden">
|
||||||
<label for="name">Nombre</label>
|
<label for="edit-name">Nombre</label>
|
||||||
<input name="name" value="" placeholder="João Gilberto" required />
|
<input id="edit-name" name="name" value="" placeholder="João Gilberto" required />
|
||||||
|
|
||||||
<label for="greeting">Saludo</label>
|
<label for="edit-edit-greeting">Saludo</label>
|
||||||
<input name="greeting" placeholder="Olá Joãzinho!" />
|
<input id="edit-greeting" name="greeting" placeholder="Olá Joãzinho!" />
|
||||||
|
|
||||||
<label for="password">Password</label>
|
<label for="edit-password">Password</label>
|
||||||
<input type="password" name="password" />
|
<input id="edit-password" type="password" name="password" />
|
||||||
|
|
||||||
<label for="schedule">Horarios</label>
|
<label for="edit-schedule">Horarios</label>
|
||||||
<input type="text" name="schedule" placeholder="days=1-5 hours=8-20:35" autocorrect="off"/>
|
<input id="edit-schedule" type="text" name="schedule" placeholder="days=1-5 hours=8-20:35" autocorrect="off"/>
|
||||||
|
|
||||||
<label for="expires">Expires</label>
|
<label for="edit-expires">Expires</label>
|
||||||
<input type="datetime-local" name="expires" placeholder="2023-01-01T00:00:00Z" />
|
<input id="edit-expires" type="datetime-local" name="expires" placeholder="2023-01-01T00:00:00Z" />
|
||||||
|
|
||||||
<label for="ttl">TTL</label>
|
<label for="edit-ttl">TTL</label>
|
||||||
<input type="text" name="max_ttl" placeholder="30d" autocorrect="off"/>
|
<input id="edit-max_ttl" type="text" name="max_ttl" placeholder="30d" autocorrect="off"/>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<input type="checkbox" name="is_admin" /><label for="admin">Admin?</label>
|
<input id="edit-is_admin" type="checkbox" name="is_admin" /><label for="edit-admin">Admin?</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<input type="checkbox" name="second_factor" /><label for="admin">Requiere 2FA?</label>
|
<input id="edit-second_factor" type="checkbox" name="second_factor" /><label for="edit-second_factor">Requiere 2FA?</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="actions">
|
<div id="actions">
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
<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" />
|
||||||
|
<!-- link rel="manifest" href="/static/manifest.webmanifest" /-->
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<header id="main-header">
|
<header id="main-header">
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
<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" />
|
||||||
|
<!--link rel="manifest" href="/static/manifest.webmanifest" /-->
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<header id="main-header">
|
<header id="main-header">
|
||||||
|
@ -19,12 +20,12 @@
|
||||||
</header>
|
</header>
|
||||||
<main class="container">
|
<main class="container">
|
||||||
<form id="login" method="post" action="/api/login">
|
<form id="login" method="post" action="/api/login">
|
||||||
<span class="error"></span>
|
<h2 class="error"></h2>
|
||||||
<label for="user">Usuario</label>
|
<label for="user">Usuario</label>
|
||||||
<input type="text" name="user" autocorrect="false" />
|
<input id="user" type="text" name="user" autocorrect="false" />
|
||||||
|
|
||||||
<label for="password">Password</label>
|
<label for="password">Password</label>
|
||||||
<input type="password" name="password" />
|
<input id="password" type="password" name="password" />
|
||||||
<button id="auth" type="submit">Iniciar Sesión</button>
|
<button id="auth" type="submit">Iniciar Sesión</button>
|
||||||
</form>
|
</form>
|
||||||
</main>
|
</main>
|
||||||
|
|
|
@ -11,6 +11,10 @@ button {
|
||||||
transition: all ease-in-out .5s;
|
transition: all ease-in-out .5s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
#rex {
|
#rex {
|
||||||
font-size: 5em;
|
font-size: 5em;
|
||||||
border-radius: 100%;
|
border-radius: 100%;
|
||||||
|
@ -76,13 +80,16 @@ input[type=checkbox] {
|
||||||
height: .8em;
|
height: .8em;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 768px) {
|
|
||||||
input {
|
|
||||||
max-width: auto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.hidden {
|
.hidden {
|
||||||
display: none
|
display: none
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 768px) {
|
||||||
|
input {
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
button {
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
{
|
||||||
|
"background_color": "#ffc6d7",
|
||||||
|
"description": "Abre la puerta del Castillo de Chapultebob",
|
||||||
|
"display": "fullscreen",
|
||||||
|
"icons": [
|
||||||
|
{
|
||||||
|
"src": "static/icon@192.png",
|
||||||
|
"sizes": "192x192",
|
||||||
|
"type": "image/png"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "Puerta Nidito",
|
||||||
|
"short_name": "Puerta",
|
||||||
|
"start_url": "/"
|
||||||
|
}
|
|
@ -6,13 +6,12 @@ importScripts(
|
||||||
|
|
||||||
workbox.loadModule('workbox-strategies');
|
workbox.loadModule('workbox-strategies');
|
||||||
|
|
||||||
|
|
||||||
self.addEventListener("install", event => {
|
self.addEventListener("install", event => {
|
||||||
console.log("Service worker installed");
|
console.log("Service worker installed");
|
||||||
|
|
||||||
const urlsToCache = ["/login", "/", "index.css", "/index.js", "/login.js", "/webauthn.js"];
|
const urlsToCache = ["/login", "/", "index.css", "/index.js", "/login.js", "/webauthn.js"];
|
||||||
event.waitUntil(
|
event.waitUntil(
|
||||||
caches.open("pwa-assets")
|
caches.open("assets")
|
||||||
.then(cache => {
|
.then(cache => {
|
||||||
return cache.addAll(urlsToCache);
|
return cache.addAll(urlsToCache);
|
||||||
})
|
})
|
||||||
|
|
|
@ -66,7 +66,7 @@ func (ttl *TTL) Scan(value any) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if value == "" {
|
if src == "" {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,7 +99,7 @@ func (ttl *TTL) FromNow() time.Time {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ttl *TTL) Seconds() int {
|
func (ttl *TTL) Seconds() int {
|
||||||
return int(ttl.duration)
|
return int(ttl.duration.Seconds())
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ sql.Scanner = &TTL{}
|
var _ sql.Scanner = &TTL{}
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
package user_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"git.rob.mx/nidito/puerta/internal/user"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestParse(t *testing.T) {
|
||||||
|
ttl := user.TTL{}
|
||||||
|
err := ttl.Scan("")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed scanning empty string: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = ttl.Scan("7d")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed scanning 7d: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if ttl.Seconds() != 604800 {
|
||||||
|
t.Fatalf("parsed bad seconds %d", ttl.Seconds())
|
||||||
|
}
|
||||||
|
|
||||||
|
// conn := sqlite.ConnectionURL{
|
||||||
|
// Database: "test.db",
|
||||||
|
// Options: map[string]string{
|
||||||
|
// "_journal": "WAL",
|
||||||
|
// "_busy_timeout": "5000",
|
||||||
|
// },
|
||||||
|
// }
|
||||||
|
|
||||||
|
// _db, err := sqlite.Open(conn)
|
||||||
|
// if err != nil {
|
||||||
|
// t.Fatal(err)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// user := &user.User{}
|
||||||
|
// if err := _db.Get(user, db.Cond{"handle": "test"}); err != nil {
|
||||||
|
// t.Fatalf("could not get user: %s", err)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// t.Fatalf("user ttl (%v): %d, from now: %s", user.TTL, user.TTL.Seconds(), user.TTL.FromNow())
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMarshalDB(t *testing.T) {
|
||||||
|
ttl := user.TTL{}
|
||||||
|
|
||||||
|
err := ttl.Scan("7d")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed scanning 7d: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if ttl.Seconds() != 60*60*24*7 {
|
||||||
|
t.Fatalf("parsed bad seconds %d", ttl.Seconds())
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := ttl.MarshalDB()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("could not marshal ttl %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := `"7d"`
|
||||||
|
if fmt.Sprintf("%s", data) != expected {
|
||||||
|
t.Fatalf("encoded data mismatch. expected %s, got %s", expected, data)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue