diff --git a/internal/auth/user.go b/internal/auth/user.go index a07b64c..a6e454c 100644 --- a/internal/auth/user.go +++ b/internal/auth/user.go @@ -41,15 +41,15 @@ func UserFromContext(req *http.Request) *User { type User struct { ID int `db:"id" json:"-"` - Handle string `db:"user" json:"user"` + Handle string `db:"handle" json:"handle"` Name string `db:"name" json:"name"` - Password string `db:"password" json:"password"` + Password string `db:"password" json:"-"` Schedule *UserSchedule `db:"schedule,omitempty" json:"schedule"` Expires *time.Time `db:"expires,omitempty" json:"expires"` Greeting string `db:"greeting" json:"greeting"` TTL *TTL `db:"max_ttl,omitempty" json:"max_ttl"` Require2FA bool `db:"second_factor" json:"second_factor"` - IsAdmin bool `db:"is_admin" json:"admin"` + IsAdmin bool `db:"is_admin" json:"is_admin"` credentials []*Credential } @@ -140,4 +140,6 @@ func (user *User) Login(password string) error { return nil } +// implement interfaces var _ = db.Record(&User{}) +var _ = webauthn.User(&User{}) diff --git a/internal/server/admin.html b/internal/server/admin.html index f7de703..c33d76d 100644 --- a/internal/server/admin.html +++ b/internal/server/admin.html @@ -18,7 +18,7 @@
-
+
- diff --git a/internal/server/server.go b/internal/server/server.go index 1cb6752..e7b71f3 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -180,8 +180,7 @@ func Initialize(config *Config) (http.Handler, error) { router.POST("/api/rex", am.Enforce2FA(rex)) router.GET("/admin", am.RequireAdmin(renderTemplate(adminTemplate))) router.GET("/api/user", am.RequireAdmin(listUsers)) - // router.GET("/api/user/:id", am.RequireAdmin(getUser)) - router.GET("/api/user/:id", getUser) + router.GET("/api/user/:id", am.RequireAdmin(getUser)) router.PUT("/api/user", am.RequireAdmin(am.Enforce2FA(createUser))) router.POST("/api/user/:id", am.RequireAdmin(am.Enforce2FA(updateUser))) router.DELETE("/api/user/:id", am.RequireAdmin(am.Enforce2FA(deleteUser))) diff --git a/internal/server/static/admin.js b/internal/server/static/admin.js index ec143f0..4bea086 100644 --- a/internal/server/static/admin.js +++ b/internal/server/static/admin.js @@ -1,32 +1,35 @@ const button = document.querySelector("#open button") const form = document.querySelector("#open") -const { create: createCredentials, get: getCredentials } = hankoWebAuthn; const userList = document.querySelector("#user-list > ul") +class UserInfoPanel extends HTMLElement { + constructor(user) { + super() + let template = document.getElementById("user-info-panel") + const shadowRoot = this.attachShadow({ mode: "open" }) + const panel = template.content.cloneNode(true) + + let handle = user.handle + panel.querySelector('h3').innerHTML = user.name + panel.querySelector('input[name=name]').value = user.name + + panel.querySelector('form').action = panel.querySelector('form').action.replace(":id", handle) + panel.querySelector('pre').textContent = handle + + panel.querySelector('input[name=greeting]').value = user.greeting + panel.querySelector('input[name=schedule]').value = user.schedule + panel.querySelector('input[name=expires]').value = user.expires + panel.querySelector('input[name=max_ttl]').value = user.max_ttl + panel.querySelector('input[name=is_admin]').checked = user.is_admin + panel.querySelector('input[name=second_factor]').checked = user.second_factor + shadowRoot.appendChild(panel) + } +} customElements.define( "user-info-panel", - class extends HTMLElement { - constructor() { - super() - let template = document.getElementById("user-info-panel") - const shadowRoot = this.attachShadow({ mode: "open" }) - const panel = template.content.cloneNode(true) - - panel.querySelector('h3').textContent = this.getAttribute('name') - panel.querySelector('name').value = this.getAttribute('name') - panel.querySelector('pre').textContent = this.getAttribute('handle') - - panel.querySelector('greeting').value = this.getAttribute('greeting') - panel.querySelector('schedule').value = this.getAttribute('schedule') - panel.querySelector('expires').value = this.getAttribute('expires') - panel.querySelector('max_ttl').value = this.getAttribute('ttl') - panel.querySelector('is_admin').checked = this.hasAttribute('admin') - panel.querySelector('second_factor').checked = this.hasAttribute('second_factor') - shadowRoot.appendChild(panel) - } - } + UserInfoPanel ); async function fetchUsers() { @@ -46,25 +49,26 @@ async function fetchUsers() { return } - userList.replaceChildren(json.map(u => { - const ip = document.createElement("user-info-panel") - ip.setAttribute("name", u.name) - ip.setAttribute("handle", u.handle) + json.forEach(u => { + const ip = new UserInfoPanel(u) + ip.setAttribute("data-name", u.name) + ip.setAttribute("data-handle", u.handle) - ip.setAttribute('greeting', u.greeting) - ip.setAttribute('schedule', u.schedule) - ip.setAttribute('expires', u.expires) - ip.setAttribute('max_ttl', u.ttl) + ip.setAttribute('data-greeting', u.greeting) + ip.setAttribute('data-schedule', u.schedule) + ip.setAttribute('data-expires', u.expires) + ip.setAttribute('data-max_ttl', u.max_ttl) if (u.admin) { - ip.setAttribute('is_admin', "") + ip.setAttribute('data-is_admin', "") } if (u.second_factor) { - ip.setAttribute('second_factor', "") + ip.setAttribute('data-second_factor', "") } - return ip - })) + return userList.append(ip) + }) } - - +window.addEventListener("load", async function() { + await fetchUsers() +})