Download db backup from admin page.

This commit is contained in:
Jamie Holdstock 2020-06-12 14:32:29 +01:00 committed by David Hill
parent d53676a907
commit bfeddd25d1
5 changed files with 35 additions and 5 deletions

View File

@ -6,7 +6,9 @@ import (
"crypto/rand"
"encoding/binary"
"fmt"
"net/http"
"os"
"strconv"
"sync"
"time"
@ -247,3 +249,17 @@ func (vdb *VspDatabase) GetCookieSecret() ([]byte, error) {
return cookieSecret, err
}
// BackupDB streams a backup of the database over an http response writer.
func (vdb *VspDatabase) BackupDB(w http.ResponseWriter) error {
w.Header().Set("Content-Type", "application/octet-stream")
w.Header().Set("Content-Disposition", `attachment; filename="vspd.db"`)
err := vdb.db.View(func(tx *bolt.Tx) error {
w.Header().Set("Content-Length", strconv.Itoa(int(tx.Size())))
_, err := tx.WriteTo(w)
return err
})
return err
}

View File

@ -14,8 +14,8 @@ func adminPage(c *gin.Context) {
})
}
// ticketSearch is the handler for "POST /admin/ticket". The "hash" param will
// be used to retrieve a ticket from the database.
// ticketSearch is the handler for "POST /admin/ticket". The hash param will be
// used to retrieve a ticket from the database.
func ticketSearch(c *gin.Context) {
hash := c.PostForm("hash")
@ -59,6 +59,16 @@ func adminLogout(c *gin.Context) {
setAdminStatus(nil, c)
}
// downloadDatabaseBackup is the handler for "GET /backup". A binary
// representation of the whole database is generated and returned to the client.
func downloadDatabaseBackup(c *gin.Context) {
err := db.BackupDB(c.Writer)
if err != nil {
log.Errorf("Error backing up database: %v", err)
c.String(http.StatusInternalServerError, "Error backing up database")
}
}
// setAdminStatus stores the authentication status of the current session and
// redirects the client to GET /admin.
func setAdminStatus(admin interface{}, c *gin.Context) {

View File

@ -4,13 +4,16 @@
<section>
<h3>Admin</h3>
<a class="btn btn-primary" href="/admin/backup" download>Backup Database</a>
<form class="my-2" action="/admin/logout" method="post">
<button type="submit">Logout</button>
<button class="btn btn-primary" type="submit">Logout</button>
</form>
<form class="my-2" action="/admin/ticket" method="post">
<input type="text" name="hash" size="64" minlength="64" maxlength="64" required placeholder="Ticket hash">
<button type="submit">Search</button>
<button class="btn btn-primary" type="submit">Search</button>
</form>
{{ with .SearchResult }}

View File

@ -4,7 +4,7 @@
<h3>Login</h3>
<form action="/admin" method="post">
<input type="password" name="password" required placeholder="Enter password">
<button type="submit">Login</button>
<button class="btn btn-primary" type="submit">Login</button>
</form>
{{ if .IncorrectPassword }}

View File

@ -207,6 +207,7 @@ func router(debugMode bool, cookieSecret []byte, dcrd rpc.DcrdConnect, wallets r
)
admin.GET("", adminPage)
admin.POST("/ticket", ticketSearch)
admin.GET("/backup", downloadDatabaseBackup)
admin.POST("/logout", adminLogout)
// These API routes access dcrd and the voting wallets, and they need