Skip to content
This repository has been archived by the owner on Jul 12, 2023. It is now read-only.

List recent codes on code-status page #774

Merged
merged 1 commit into from
Oct 7, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 27 additions & 3 deletions cmd/server/assets/codestatus/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ <h1>Verification code status</h1>
<div class="card mb-3 shadow-sm">
<div class="card-header">Code status</div>
<div class="card-body">
<form method="POST" action="show" class="floating-form">
<form method="POST" id="code-form" action="show" class="floating-form">
{{ .csrfField }}
<div class="form-group">
<div class="form-label-group ">
Expand All @@ -43,17 +43,36 @@ <h1>Verification code status</h1>
</div>
</div>

<button id="submit" class="btn btn-primary btn-block">Check status</button>
<button class="btn btn-primary btn-block">Check status</button>
</form>
</div>
</div>

<div class="card mb-3 shadow-sm">
<div class="card-header">Recently issued codes</div>
<div class="card-body">
<div class="list-group">
{{range $code := .recentCodes}}
<a class="list-group-item list-group-item-action" onclick="clickCode('{{$code.UUID}}')">
{{$code.UUID}}
<small class="form-text text-muted">
Created at: {{$code.CreatedAt}}
</small>
</a>
{{end}}
</div>
</div>
</div>
</main>

{{template "scripts" .}}
<script type="text/javascript">
let $uuid
let $form

$(function() {
let $uuid = $('#uuid');
$uuid = $('#uuid');
$form = $('#code-form');
let allowedChars = new RegExp("[0-9a-fA-F]");
let dashLocations = [8, 13, 18, 23];

Expand All @@ -73,6 +92,11 @@ <h1>Verification code status</h1>
$uuid.val(r);
});
});

function clickCode(uuid) {
$uuid.val(uuid);
$form.submit();
}
</script>
</body>

Expand Down
16 changes: 15 additions & 1 deletion pkg/controller/codestatus/expire.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,18 @@ func (c *Controller) HandleExpirePage() http.Handler {
ctx := r.Context()
vars := mux.Vars(r)

realm := controller.RealmFromContext(ctx)
if realm == nil {
controller.MissingRealm(w, r, c.h)
return
}

currentUser := controller.UserFromContext(ctx)
if currentUser == nil {
controller.MissingUser(w, r, c.h)
return
}

session := controller.SessionFromContext(ctx)
if session == nil {
controller.MissingSession(w, r, c.h)
Expand All @@ -69,7 +81,9 @@ func (c *Controller) HandleExpirePage() http.Handler {
code, _, apiErr := c.CheckCodeStatus(r, vars["uuid"])
if apiErr != nil {
flash.Error("Failed to expire code: %v.", apiErr.Error)
c.renderStatus(ctx, w, code)
if err := c.renderStatus(ctx, w, realm, currentUser, code); err != nil {
controller.InternalError(w, r, c.h, err)
}
return
}

Expand Down
30 changes: 27 additions & 3 deletions pkg/controller/codestatus/index.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,39 @@ func (c *Controller) HandleIndex() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()

// TODO(whaught): load a list of recent codes to show
realm := controller.RealmFromContext(ctx)
if realm == nil {
controller.MissingRealm(w, r, c.h)
return
}

currentUser := controller.UserFromContext(ctx)
if currentUser == nil {
controller.MissingUser(w, r, c.h)
return
}

var code database.VerificationCode
c.renderStatus(ctx, w, &code)
if err := c.renderStatus(ctx, w, realm, currentUser, &code); err != nil {
controller.InternalError(w, r, c.h, err)
}
})
}

func (c *Controller) renderStatus(ctx context.Context, w http.ResponseWriter, code *database.VerificationCode) {
func (c *Controller) renderStatus(
ctx context.Context,
w http.ResponseWriter,
realm *database.Realm,
user *database.User,
code *database.VerificationCode) error {
recentCodes, err := c.db.ListRecentCodes(realm, user)
if err != nil {
return err
}

m := controller.TemplateMapFromContext(ctx)
m["code"] = code
m["recentCodes"] = recentCodes
c.h.RenderHTML(w, "code/status", m)
return nil
}
20 changes: 18 additions & 2 deletions pkg/controller/codestatus/show.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,18 @@ func (c *Controller) HandleShow() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()

realm := controller.RealmFromContext(ctx)
if realm == nil {
controller.MissingRealm(w, r, c.h)
return
}

currentUser := controller.UserFromContext(ctx)
if currentUser == nil {
controller.MissingUser(w, r, c.h)
return
}

session := controller.SessionFromContext(ctx)
if session == nil {
controller.MissingSession(w, r, c.h)
Expand All @@ -53,7 +65,9 @@ func (c *Controller) HandleShow() http.Handler {
var code database.VerificationCode
code.AddError("uuid", "cannot be blank")

c.renderStatus(ctx, w, &code)
if err := c.renderStatus(ctx, w, realm, currentUser, &code); err != nil {
controller.InternalError(w, r, c.h, err)
}
return
}

Expand All @@ -63,7 +77,9 @@ func (c *Controller) HandleShow() http.Handler {
code.UUID = form.UUID
code.AddError("uuid", apiErr.Error)

c.renderStatus(ctx, w, &code)
if err := c.renderStatus(ctx, w, realm, currentUser, &code); err != nil {
controller.InternalError(w, r, c.h, err)
}
return
}

Expand Down
2 changes: 1 addition & 1 deletion pkg/database/token.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ func (db *Database) ClaimToken(realmID uint, tokenID string, subject *Subject) e
})
}

// VerifyCodeAndIssueToken takes a previously issed verification code and exchanges
// VerifyCodeAndIssueToken takes a previously issued verification code and exchanges
// it for a long term token. The verification code must not have expired and must
// not have been previously used. Both acctions are done in a single database
// transaction.
Expand Down
27 changes: 27 additions & 0 deletions pkg/database/vercode.go
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,33 @@ func (db *Database) FindVerificationCodeByUUID(uuid string) (*VerificationCode,
return &vc, nil
}

// ListRecentCodes shows the last 5 recently issued codes for a given issuing user.
// The code and longCode are removed, this is only intended to show metadata.
func (db *Database) ListRecentCodes(realm *Realm, user *User) ([]*VerificationCode, error) {
var codes []*VerificationCode
if err := db.db.
Model(&VerificationCode{}).
Where("realm_id = ? AND issuing_user_id = ?", realm.ID, user.ID).
Order("created_at DESC").
Limit(5).
Find(&codes).
Error; err != nil {
return nil, err
}

// We're only showing meta details, not the encrypted codes.
for _, t := range codes {
if t.Code != "" {
t.Code = "short"
}
if t.LongCode != "" {
t.LongCode = "long"
}
}

return codes, nil
}

// ExpireCode saves a verification code as expired.
func (db *Database) ExpireCode(uuid string) (*VerificationCode, error) {
var vc VerificationCode
Expand Down
39 changes: 39 additions & 0 deletions pkg/database/vercode_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,45 @@ func TestVerificationCode_FindVerificationCodeByUUID(t *testing.T) {
}
}

func TestVerificationCode_ListRecentCodes(t *testing.T) {
t.Parallel()

db := NewTestDatabase(t)
var realmID uint = 123
var userID uint = 456

vc := &VerificationCode{
RealmID: realmID,
IssuingUserID: userID,
Code: "123456",
LongCode: "defghijk329024",
TestType: "confirmed",
ExpiresAt: time.Now().Add(time.Hour),
LongExpiresAt: time.Now().Add(2 * time.Hour),
}

if err := db.SaveVerificationCode(vc, time.Hour); err != nil {
t.Fatal(err)
}

uuid := vc.UUID
if uuid == "" {
t.Fatal("expected uuid")
}

{
r := &Realm{Model: gorm.Model{ID: realmID}}
u := &User{Model: gorm.Model{ID: userID}}
got, err := db.ListRecentCodes(r, u)
if err != nil {
t.Fatal(err)
}
if got, want := got[0].ID, vc.ID; got != want {
t.Errorf("expected %#v to be %#v", got, want)
}
}
}

func TestVerificationCode_ExpireVerificationCode(t *testing.T) {
t.Parallel()

Expand Down