136 lines
3.3 KiB
Go
136 lines
3.3 KiB
Go
|
|
package server
|
||
|
|
|
||
|
|
import (
|
||
|
|
"net/http"
|
||
|
|
"time"
|
||
|
|
|
||
|
|
"github.com/gin-gonic/gin"
|
||
|
|
|
||
|
|
"warpbox/lib/boxstore"
|
||
|
|
"warpbox/lib/models"
|
||
|
|
)
|
||
|
|
|
||
|
|
const boxAuthCookiePrefix = "warpbox_box_"
|
||
|
|
|
||
|
|
func handleBoxLogin(ctx *gin.Context) {
|
||
|
|
boxID := ctx.Param("id")
|
||
|
|
if !boxstore.ValidBoxID(boxID) {
|
||
|
|
ctx.String(http.StatusBadRequest, "Invalid box id")
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
manifest, err := boxstore.ReadManifest(boxID)
|
||
|
|
if err != nil {
|
||
|
|
ctx.String(http.StatusNotFound, "Box not found")
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
if boxstore.IsExpired(manifest) {
|
||
|
|
boxstore.DeleteBox(boxID)
|
||
|
|
ctx.String(http.StatusGone, "Box expired")
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
if !boxstore.IsPasswordProtected(manifest) || isBoxAuthorized(ctx, boxID, manifest) {
|
||
|
|
ctx.Redirect(http.StatusSeeOther, "/box/"+boxID)
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
renderBoxLogin(ctx, boxID, "")
|
||
|
|
}
|
||
|
|
|
||
|
|
func handleBoxLoginPost(ctx *gin.Context) {
|
||
|
|
boxID := ctx.Param("id")
|
||
|
|
if !boxstore.ValidBoxID(boxID) {
|
||
|
|
ctx.String(http.StatusBadRequest, "Invalid box id")
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
manifest, err := boxstore.ReadManifest(boxID)
|
||
|
|
if err != nil {
|
||
|
|
ctx.String(http.StatusNotFound, "Box not found")
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
if boxstore.IsExpired(manifest) {
|
||
|
|
boxstore.DeleteBox(boxID)
|
||
|
|
ctx.String(http.StatusGone, "Box expired")
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
if !boxstore.VerifyPassword(manifest, ctx.PostForm("password")) {
|
||
|
|
renderBoxLogin(ctx, boxID, "The password was not accepted.")
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
maxAge := 24 * 60 * 60
|
||
|
|
if !manifest.ExpiresAt.IsZero() {
|
||
|
|
seconds := int(time.Until(manifest.ExpiresAt).Seconds())
|
||
|
|
if seconds > 0 {
|
||
|
|
maxAge = seconds
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
ctx.SetCookie(boxAuthCookieName(boxID), manifest.AuthToken, maxAge, "/box/"+boxID, "", false, true)
|
||
|
|
ctx.Redirect(http.StatusSeeOther, "/box/"+boxID)
|
||
|
|
}
|
||
|
|
func (app *App) authorizeBoxRequest(ctx *gin.Context, boxID string, wantsHTML bool) (models.BoxManifest, bool, bool) {
|
||
|
|
manifest, err := boxstore.ReadManifest(boxID)
|
||
|
|
if err != nil {
|
||
|
|
return models.BoxManifest{}, false, true
|
||
|
|
}
|
||
|
|
|
||
|
|
if boxstore.IsExpired(manifest) {
|
||
|
|
boxstore.DeleteBox(boxID)
|
||
|
|
if wantsHTML {
|
||
|
|
ctx.String(http.StatusGone, "Box expired")
|
||
|
|
} else {
|
||
|
|
ctx.JSON(http.StatusGone, gin.H{"error": "Box expired"})
|
||
|
|
}
|
||
|
|
return manifest, true, false
|
||
|
|
}
|
||
|
|
|
||
|
|
if manifest.OneTimeDownload && manifest.Consumed {
|
||
|
|
if wantsHTML {
|
||
|
|
ctx.String(http.StatusGone, "Box already consumed")
|
||
|
|
} else {
|
||
|
|
ctx.JSON(http.StatusGone, gin.H{"error": "Box already consumed"})
|
||
|
|
}
|
||
|
|
return manifest, true, false
|
||
|
|
}
|
||
|
|
|
||
|
|
if boxstore.IsPasswordProtected(manifest) && !isBoxAuthorized(ctx, boxID, manifest) {
|
||
|
|
if wantsHTML {
|
||
|
|
ctx.Redirect(http.StatusSeeOther, "/box/"+boxID+"/login")
|
||
|
|
} else {
|
||
|
|
ctx.JSON(http.StatusUnauthorized, gin.H{"error": "Password required"})
|
||
|
|
}
|
||
|
|
return manifest, true, false
|
||
|
|
}
|
||
|
|
|
||
|
|
if app.config.RenewOnAccessEnabled {
|
||
|
|
if renewed, err := boxstore.RenewManifest(boxID, manifest.RetentionSecs); err == nil {
|
||
|
|
manifest = renewed
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return manifest, true, true
|
||
|
|
}
|
||
|
|
|
||
|
|
func isBoxAuthorized(ctx *gin.Context, boxID string, manifest models.BoxManifest) bool {
|
||
|
|
token, err := ctx.Cookie(boxAuthCookieName(boxID))
|
||
|
|
return err == nil && boxstore.VerifyAuthToken(manifest, token)
|
||
|
|
}
|
||
|
|
|
||
|
|
func boxAuthCookieName(boxID string) string {
|
||
|
|
return boxAuthCookiePrefix + boxID
|
||
|
|
}
|
||
|
|
|
||
|
|
func renderBoxLogin(ctx *gin.Context, boxID string, errorMessage string) {
|
||
|
|
ctx.HTML(http.StatusOK, "box_login.html", gin.H{
|
||
|
|
"BoxID": boxID,
|
||
|
|
"BoxUser": "WarpBox\\" + boxID,
|
||
|
|
"ErrorMessage": errorMessage,
|
||
|
|
})
|
||
|
|
}
|