cacher/save_cache.go

156 lines
3.4 KiB
Go

package main
import (
"database/sql"
"encoding/json"
"io"
"log"
"net/http"
"os"
"path"
"strings"
"github.com/jmoiron/sqlx"
gonanoid "github.com/matoous/go-nanoid/v2"
"github.com/mattn/go-sqlite3"
)
func badRequest(w http.ResponseWriter) {
http.Error(w, "bad request", http.StatusBadRequest)
}
func getAdminAuth(w http.ResponseWriter, req *http.Request) bool {
auth := req.Header.Get("Authorization")
if len(auth) == 0 {
badRequest(w)
return false
}
if auth == "Bearer "+admin_secret {
return true
}
return false
}
func (r *cache) getCache(w http.ResponseWriter, req *http.Request, name string) *dbCache {
auth := req.Header.Get("Authorization")
if len(auth) == 0 {
badRequest(w)
return nil
}
var c dbCache
err := r.db.Get(&c, "SELECT secret FROM caches WHERE name = ?", name)
if err != nil {
if err == sql.ErrNoRows {
http.Error(w, "cache doesn't exist", http.StatusNotFound)
} else {
log.Printf("Get(SELECT): %w", err)
http.Error(w, "server error", http.StatusInternalServerError)
}
return nil
}
if auth == "Bearer "+c.Secret {
return &c
} else {
http.Error(w, "wrong secret", http.StatusUnauthorized)
return nil
}
}
type cache struct {
db *sqlx.DB
}
type dbCache struct {
Secret string
}
type responseNewCache struct {
Secret string `json:"secret"`
}
func (r *cache) ServeHTTP(w http.ResponseWriter, req *http.Request) {
parts := strings.Split(req.URL.Path[1:], "/")
log.Println(parts)
if len(parts) != 2 {
http.Error(w, "wrong amount of parts", http.StatusBadRequest)
return
}
name := parts[1]
if req.Method == "POST" {
if !getAdminAuth(w, req) {
return
}
if strings.ContainsAny(name, "/") {
badRequest(w)
return
}
secret, err := gonanoid.New()
if err != nil {
log.Printf("Error generating ID: %w", err)
http.Error(w, "server error", http.StatusInternalServerError)
return
}
_, err = r.db.Exec("INSERT INTO caches(name, secret) VALUES(?, ?)", name, secret)
if err != nil {
if err.(sqlite3.Error).Code == sqlite3.ErrConstraint {
http.Error(w, "cache already exists", http.StatusConflict)
} else {
log.Printf("Error saving cache DB entry: %w", err)
http.Error(w, "server error", http.StatusInternalServerError)
}
return
}
byt, err := json.Marshal(responseNewCache{Secret: secret})
if err != nil {
log.Printf("Marshal: %w", err)
http.Error(w, "server error", http.StatusInternalServerError)
return
}
w.Header().Add("Content-Encoding", "application/json")
w.Write(byt)
} else if req.Method == "PUT" {
c := r.getCache(w, req, name)
if c == nil {
return
}
file, err := os.Create(path.Join("./files/", name))
if err != nil {
log.Printf("os.Create: %w", err)
http.Error(w, "server error", http.StatusInternalServerError)
return
}
_, err = io.Copy(file, req.Body)
if err != nil {
log.Printf("io.Copy: %w", err)
http.Error(w, "server error", http.StatusInternalServerError)
return
}
} else if req.Method == "GET" {
c := r.getCache(w, req, name)
if c == nil {
return
}
file, err := os.Open(path.Join("./files/", name))
if err != nil {
log.Printf("os.Open: %w", err)
http.Error(w, "server error", http.StatusInternalServerError)
return
}
_, err = io.Copy(w, file)
if err != nil {
log.Printf("io.Copy: %w", err)
http.Error(w, "server error", http.StatusInternalServerError)
return
}
} else {
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
return
}
}